Class: SpaceArchitect::Space

Inherits:
Object
  • Object
show all
Defined in:
lib/space_architect/space.rb

Constant Summary collapse

METADATA_FILE =
"space.yaml"
VALID_STATUSES =
%w[active paused done archived].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, data) ⇒ Space

Returns a new instance of Space.



28
29
30
31
# File 'lib/space_architect/space.rb', line 28

def initialize(path, data)
  @path = Pathname.new(path)
  @data = data
end

Instance Attribute Details

#dataObject (readonly)

Returns the value of attribute data.



12
13
14
# File 'lib/space_architect/space.rb', line 12

def data
  @data
end

#pathObject (readonly)

Returns the value of attribute path.



12
13
14
# File 'lib/space_architect/space.rb', line 12

def path
  @path
end

Class Method Details

.load(path) ⇒ Object

Raises:



14
15
16
17
18
19
20
21
22
# File 'lib/space_architect/space.rb', line 14

def self.load(path)
   = Pathname.new(path).join(METADATA_FILE)
  raise NotFoundError, "No space metadata found at #{}" unless .exist?

  parsed = YAML.safe_load(.read, aliases: false) || {}
  raise Error, "Space metadata must contain a YAML mapping: #{}" unless parsed.is_a?(Hash)

  new(Pathname.new(path), stringify_keys(parsed))
end

.stringify_keys(hash) ⇒ Object



24
25
26
# File 'lib/space_architect/space.rb', line 24

def self.stringify_keys(hash)
  hash.each_with_object({}) { |(key, value), result| result[key.to_s] = value }
end

Instance Method Details

#add_repo(reference, relative_path:, now: Time.now) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/space_architect/space.rb', line 79

def add_repo(reference, relative_path:, now: Time.now)
  repo_data = repo_data_for(reference, relative_path:, now:)
  existing = repos.find do |repo|
    repo["full_name"] == repo_data["full_name"] ||
      repo["path"] == repo_data["path"] ||
      repo["name"] == repo_data["name"]
  end
  if existing
    raise RepoExistsError, "Repo '#{repo_data['full_name']}' already exists in #{id}"
  end

  data["repos"] = repos + [repo_data]
  data["updated_at"] = now.iso8601
  save
  repo_data
end

#architectObject



51
52
53
# File 'lib/space_architect/space.rb', line 51

def architect
  data["architect"]
end

#architect=(val) ⇒ Object



55
56
57
# File 'lib/space_architect/space.rb', line 55

def architect=(val)
  data["architect"] = val
end

#idObject



33
34
35
# File 'lib/space_architect/space.rb', line 33

def id
  data.fetch("id")
end

#metadata_pathObject



59
60
61
# File 'lib/space_architect/space.rb', line 59

def 
  path.join(METADATA_FILE)
end

#reposObject



45
46
47
48
49
# File 'lib/space_architect/space.rb', line 45

def repos
  Array(data["repos"]).map do |repo|
    repo.is_a?(Hash) ? self.class.stringify_keys(repo) : { "name" => repo.to_s }
  end
end

#saveObject



63
64
65
66
# File 'lib/space_architect/space.rb', line 63

def save
  AtomicWrite.write(, YAML.dump(data))
  self
end

#statusObject



41
42
43
# File 'lib/space_architect/space.rb', line 41

def status
  data.fetch("status", "active")
end

#titleObject



37
38
39
# File 'lib/space_architect/space.rb', line 37

def title
  data.fetch("title")
end

#update_status(status, now: Time.now) ⇒ Object



68
69
70
71
72
73
74
75
76
77
# File 'lib/space_architect/space.rb', line 68

def update_status(status, now: Time.now)
  normalized = status.to_s.downcase
  unless VALID_STATUSES.include?(normalized)
    raise InvalidStatusError, "Invalid status '#{status}'. Expected one of: #{VALID_STATUSES.join(', ')}"
  end

  data["status"] = normalized
  data["updated_at"] = now.iso8601
  save
end