Class: Agentilda::Creator

Inherits:
Object
  • Object
show all
Defined in:
lib/agentilda/creator.rb

Overview

Mints new plan folders. Backs /spec-create.

Every failure is a Failure, never an exception: creating a folder is the one place a typo becomes permanent, so the caller is made to look.

Constant Summary collapse

DEFAULT_STATUS =

The state a new plan opens in — a specification and nothing else yet.

:new
RETROACTIVE_STATUS =

The state a retroactive plan is born in: the work is live, but it has neither a specification nor a plan.

:retroactive

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dir:) ⇒ Creator

Returns a new instance of Creator.

Parameters:

  • dir (String)

    the .plans directory



19
20
21
# File 'lib/agentilda/creator.rb', line 19

def initialize(dir:)
  @dir = File.expand_path(dir)
end

Instance Attribute Details

#dirString (readonly)

Returns the .plans directory.

Returns:

  • (String)

    the .plans directory



24
25
26
# File 'lib/agentilda/creator.rb', line 24

def dir
  @dir
end

Class Method Details

.slugify(words) ⇒ String

Turn free text into the kebab tail of a folder name.

Parameters:

  • words (Array<String>, String)

Returns:

  • (String)

    possibly empty, which the caller must reject



64
65
66
# File 'lib/agentilda/creator.rb', line 64

def self.slugify(words)
  Array(words).join(" ").downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-+|-+\z/, "")
end

Instance Method Details

#create(words:, after: nil, status: nil, prs: nil) ⇒ Dry::Monads::Result

Create a plan folder.

Parameters:

  • words (Array<String>)

    the topic; becomes the slug

  • after (String, nil) (defaults to: nil)

    anchor for a retroactive plan, e.g. "002"

  • status (String, Symbol, nil) (defaults to: nil)

    override the default state

  • prs (Array<Hash>, nil) (defaults to: nil)

    pull requests to record, already fetched; their presence is what makes the folder 🕰️ Retroactive rather than ⚪️

Returns:

  • (Dry::Monads::Result)

    Success(absolute path) or Failure(message)



34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/agentilda/creator.rb', line 34

def create(words:, after: nil, status: nil, prs: nil)
  resolved = resolve_status(status, after) or
    return Failure("unknown status: #{status}")

  slug = self.class.slugify(words)
  return Failure("the topic produced an empty slug") if slug.empty?

  ordinal = after ? retroactive_ordinal(after) : Ordinal.next_major(existing)
  return ordinal if ordinal.is_a?(Dry::Monads::Result)

  build(ordinal, resolved, slug).fmap { |path| record_pull_requests(path, prs) }
rescue Agentilda::Error => e
  Failure(e.message)
end

#existingArray<Agentilda::Ordinal>

Returns every number already taken.

Returns:



50
51
52
53
54
55
56
57
58
# File 'lib/agentilda/creator.rb', line 50

def existing
  @existing ||= begin
    return [] unless File.directory?(dir)

    Dir.children(dir)
      .select { |c| File.directory?(File.join(dir, c)) }
      .filter_map { |c| Ordinal.from_dirname(c) }
  end
end