umwelt 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.circleci/config.yml +46 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +28 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +79 -0
- data/LICENSE.txt +21 -0
- data/README.md +75 -0
- data/Rakefile +12 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/umwelt +7 -0
- data/lib/umwelt.rb +23 -0
- data/lib/umwelt/abstract.rb +7 -0
- data/lib/umwelt/abstract/file.rb +7 -0
- data/lib/umwelt/abstract/file/restore.rb +48 -0
- data/lib/umwelt/abstract/file/store.rb +44 -0
- data/lib/umwelt/abstract/mapper.rb +17 -0
- data/lib/umwelt/cli.rb +6 -0
- data/lib/umwelt/cli/commands.rb +15 -0
- data/lib/umwelt/cli/commands/clone.rb +16 -0
- data/lib/umwelt/cli/commands/convey.rb +57 -0
- data/lib/umwelt/cli/commands/pull.rb +11 -0
- data/lib/umwelt/cli/commands/version.rb +9 -0
- data/lib/umwelt/command.rb +6 -0
- data/lib/umwelt/command/convey.rb +84 -0
- data/lib/umwelt/episode.rb +7 -0
- data/lib/umwelt/episode/file.rb +7 -0
- data/lib/umwelt/episode/file/restore.rb +22 -0
- data/lib/umwelt/episode/file/store.rb +15 -0
- data/lib/umwelt/episode/mapper.rb +33 -0
- data/lib/umwelt/fragment.rb +6 -0
- data/lib/umwelt/fragment/mapper.rb +11 -0
- data/lib/umwelt/history.rb +10 -0
- data/lib/umwelt/history/aggregate.rb +49 -0
- data/lib/umwelt/history/file.rb +7 -0
- data/lib/umwelt/history/file/restore.rb +22 -0
- data/lib/umwelt/history/file/store.rb +15 -0
- data/lib/umwelt/history/follow.rb +32 -0
- data/lib/umwelt/history/mapper.rb +33 -0
- data/lib/umwelt/history/trace.rb +51 -0
- data/lib/umwelt/node.rb +46 -0
- data/lib/umwelt/node/build.rb +31 -0
- data/lib/umwelt/node/root.rb +6 -0
- data/lib/umwelt/node/space.rb +6 -0
- data/lib/umwelt/phase.rb +6 -0
- data/lib/umwelt/phase/mapper.rb +18 -0
- data/lib/umwelt/project.rb +7 -0
- data/lib/umwelt/project/file.rb +7 -0
- data/lib/umwelt/project/file/restore.rb +22 -0
- data/lib/umwelt/project/file/store.rb +15 -0
- data/lib/umwelt/project/mapper.rb +11 -0
- data/lib/umwelt/semantic.rb +57 -0
- data/lib/umwelt/semantic/plain.rb +12 -0
- data/lib/umwelt/semantic/plain/root.rb +13 -0
- data/lib/umwelt/semantic/plain/space.rb +13 -0
- data/lib/umwelt/structs/episode.rb +9 -0
- data/lib/umwelt/structs/fragment.rb +13 -0
- data/lib/umwelt/structs/history.rb +3 -0
- data/lib/umwelt/structs/node.rb +13 -0
- data/lib/umwelt/structs/phase.rb +13 -0
- data/lib/umwelt/structs/project.rb +10 -0
- data/lib/umwelt/structs/trunk.rb +8 -0
- data/lib/umwelt/tree.rb +8 -0
- data/lib/umwelt/tree/fill.rb +35 -0
- data/lib/umwelt/tree/imprint.rb +53 -0
- data/lib/umwelt/tree/trunk.rb +27 -0
- data/lib/umwelt/version.rb +5 -0
- data/umwelt.gemspec +56 -0
- metadata +248 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::History
|
4
|
+
class Aggregate
|
5
|
+
include Hanami::Interactor
|
6
|
+
|
7
|
+
expose :fragments
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@engaged = {}
|
11
|
+
@forgotten = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(episodes)
|
15
|
+
episodes.each do |episode|
|
16
|
+
index_engaged(episode.engaged)
|
17
|
+
collect_forgotten(episode.forgotten)
|
18
|
+
end
|
19
|
+
|
20
|
+
verify_consistency
|
21
|
+
|
22
|
+
@fragments = @engaged.slice(*alive_ids).values
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def alive_ids
|
28
|
+
@engaged.keys - @forgotten
|
29
|
+
end
|
30
|
+
|
31
|
+
def fantom_ids
|
32
|
+
@forgotten - @engaged.keys
|
33
|
+
end
|
34
|
+
|
35
|
+
def verify_consistency
|
36
|
+
fantom_ids.empty? || error!("Aggregate failed: fantom ids: #{fantom_ids}")
|
37
|
+
end
|
38
|
+
|
39
|
+
def collect_forgotten(ids)
|
40
|
+
@forgotten.push(*ids)
|
41
|
+
end
|
42
|
+
|
43
|
+
def index_engaged(fragments)
|
44
|
+
fragments.each do |fragment|
|
45
|
+
@engaged[fragment[:id]] = fragment
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../structs/history'
|
4
|
+
|
5
|
+
module Umwelt::History::File
|
6
|
+
class Restore < Umwelt::Abstract::File::Restore
|
7
|
+
def initialize(
|
8
|
+
path: '.umwelt',
|
9
|
+
mapper: Umwelt::History::Mapper
|
10
|
+
)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
@struct = struct parse read full_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def full_path
|
19
|
+
umwelt_root_path / 'history.json'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::History::File
|
4
|
+
class Store < Umwelt::Abstract::File::Store
|
5
|
+
def call(struct)
|
6
|
+
mkpath full_path.dirname
|
7
|
+
|
8
|
+
full_path.write serialize destruct struct
|
9
|
+
end
|
10
|
+
|
11
|
+
def full_path
|
12
|
+
umwelt_root_path / 'history.json'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::History
|
4
|
+
class Follow
|
5
|
+
include Hanami::Interactor
|
6
|
+
|
7
|
+
expose :episodes
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
reader: Umwelt::Episode::File::Restore,
|
11
|
+
path: '.umwelt'
|
12
|
+
)
|
13
|
+
@reader = reader.new(path: path)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(phases)
|
17
|
+
@episodes = phases.map { |phase| episode(phase) }
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def episode(phase)
|
23
|
+
restored = restore_episode(phase.id)
|
24
|
+
error! restored.errors if restored.failure?
|
25
|
+
restored.struct
|
26
|
+
end
|
27
|
+
|
28
|
+
def restore_episode(phase_id)
|
29
|
+
@reader.call(phase_id)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../structs/phase'
|
4
|
+
require_relative '../structs/project'
|
5
|
+
|
6
|
+
module Umwelt::History
|
7
|
+
class Mapper < Umwelt::Abstract::Mapper
|
8
|
+
def call(
|
9
|
+
data = {
|
10
|
+
project: {},
|
11
|
+
phases: []
|
12
|
+
}
|
13
|
+
)
|
14
|
+
|
15
|
+
@struct = Struct::History.new(
|
16
|
+
project: project(data[:project]),
|
17
|
+
phases: phases(data[:phases])
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def phases(phases_data)
|
22
|
+
phases_data.map { |phase_data| phase(phase_data) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def project(data)
|
26
|
+
fill(Struct::Project, data)
|
27
|
+
end
|
28
|
+
|
29
|
+
def phase(data)
|
30
|
+
fill(Struct::Phase, data)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::History
|
4
|
+
class Trace
|
5
|
+
include Hanami::Interactor
|
6
|
+
|
7
|
+
expose :continuity
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@queue = Queue.new # for phases
|
11
|
+
@phases_index = {}
|
12
|
+
@continuity = []
|
13
|
+
@timeline = {}
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(history, phase_id)
|
17
|
+
to_index(history.phases)
|
18
|
+
|
19
|
+
@queue.push from_index(phase_id)
|
20
|
+
|
21
|
+
loop do
|
22
|
+
break if @queue.empty?
|
23
|
+
|
24
|
+
process(@queue.pop)
|
25
|
+
end
|
26
|
+
|
27
|
+
@continuity = @timeline.values
|
28
|
+
end
|
29
|
+
|
30
|
+
def process(phase)
|
31
|
+
@timeline[phase[:id]] = phase
|
32
|
+
enqueue(phase)
|
33
|
+
end
|
34
|
+
|
35
|
+
def enqueue(phase)
|
36
|
+
@queue.push from_index(phase.merge_id) unless phase.merge_id.nil?
|
37
|
+
@queue.push from_index(phase.parent_id) unless phase.parent_id.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def from_index(phase_id)
|
41
|
+
phase = @phases_index[phase_id]
|
42
|
+
phase || error!("Phase with ID #{phase_id} not exist, but referenced")
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_index(phases)
|
46
|
+
phases.each do |phase|
|
47
|
+
@phases_index[phase[:id]] = phase
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/umwelt/node.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './structs/node'
|
4
|
+
|
5
|
+
module Umwelt::Node
|
6
|
+
class Base < Struct::Node
|
7
|
+
def semantics
|
8
|
+
[:Plain]
|
9
|
+
end
|
10
|
+
|
11
|
+
def semantic(semantic_name)
|
12
|
+
semantic_klass(semantic_name).new(node: self)
|
13
|
+
end
|
14
|
+
|
15
|
+
def ancestry
|
16
|
+
if context_id
|
17
|
+
context.ancestry << self
|
18
|
+
else
|
19
|
+
[self]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def context
|
24
|
+
tree.node(context_id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def label
|
28
|
+
self.class.name.split('::').last.to_sym
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Umwelt::Node::Space.new.semantic_klass(semantic)
|
34
|
+
# => Umwelt::Semantic::Plain::Space
|
35
|
+
def semantic_klass(semantic_name)
|
36
|
+
[semantic_name, label]
|
37
|
+
.reduce(Umwelt::Semantic) do |klass, name|
|
38
|
+
klass.const_get name
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
require_relative './node/build'
|
45
|
+
require_relative './node/root'
|
46
|
+
require_relative './node/space'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::Node
|
4
|
+
class Build
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators Hanami::Utils::String, :classify
|
7
|
+
|
8
|
+
def initialize(tree)
|
9
|
+
@tree = tree
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(frag)
|
13
|
+
node_klass(frag.kind).new(attributes(frag))
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_reader :tree
|
19
|
+
|
20
|
+
def attributes(frag)
|
21
|
+
frag
|
22
|
+
.to_h
|
23
|
+
.slice(:id, :abstract_id, :context_id, :body, :note)
|
24
|
+
.merge(tree: tree)
|
25
|
+
end
|
26
|
+
|
27
|
+
def node_klass(kind)
|
28
|
+
Umwelt::Node.const_get classify(kind)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/umwelt/phase.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../structs/phase'
|
4
|
+
|
5
|
+
module Umwelt::Phase
|
6
|
+
class Mapper < Umwelt::Abstract::Mapper
|
7
|
+
def call(data)
|
8
|
+
@struct = fill(
|
9
|
+
Struct::Phase,
|
10
|
+
data.merge(finished_at: time(data[:finished_at]))
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
def time(str)
|
15
|
+
Time.parse str if str
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../structs/history'
|
4
|
+
|
5
|
+
module Umwelt::Project::File
|
6
|
+
class Restore < Umwelt::Abstract::File::Restore
|
7
|
+
def initialize(
|
8
|
+
path: '.umwelt',
|
9
|
+
mapper: Umwelt::Project::Mapper
|
10
|
+
)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
@struct = struct parse read full_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def full_path
|
19
|
+
umwelt_root_path / 'project.json'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::Project::File
|
4
|
+
class Store < Umwelt::Abstract::File::Store
|
5
|
+
def call(struct)
|
6
|
+
mkpath full_path.dirname
|
7
|
+
|
8
|
+
full_path.write serialize destruct struct
|
9
|
+
end
|
10
|
+
|
11
|
+
def full_path
|
12
|
+
umwelt_root_path / 'project.json'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::Semantic
|
4
|
+
class Base
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators Hanami::Utils::String, :classify, :underscore
|
7
|
+
def_delegators :node, :ancestry, :body, :note
|
8
|
+
|
9
|
+
attr_reader :node
|
10
|
+
|
11
|
+
def initialize(node:)
|
12
|
+
@node = node
|
13
|
+
end
|
14
|
+
|
15
|
+
def s(type, *children)
|
16
|
+
Parser::AST::Node.new(type, children)
|
17
|
+
end
|
18
|
+
|
19
|
+
def ancestry_path
|
20
|
+
ancestry
|
21
|
+
.collect(&:body)
|
22
|
+
.map { |body| underscore(body) }
|
23
|
+
.join '/'
|
24
|
+
end
|
25
|
+
|
26
|
+
def code
|
27
|
+
Unparser.unparse(ast)
|
28
|
+
end
|
29
|
+
|
30
|
+
# default_location defined, for example,
|
31
|
+
# in Semantic::Plain::Base
|
32
|
+
# or base file from another semantic
|
33
|
+
def path(location: nil)
|
34
|
+
Pathname.pwd / (location || default_location) / tail_path
|
35
|
+
end
|
36
|
+
|
37
|
+
# nil check for case of root node, which has not context
|
38
|
+
def context
|
39
|
+
node.context&.semantic(:Plain)
|
40
|
+
end
|
41
|
+
|
42
|
+
# classified symbol
|
43
|
+
def csymbol
|
44
|
+
classify(body).to_sym
|
45
|
+
end
|
46
|
+
|
47
|
+
def label
|
48
|
+
self.class.name.split('::').last.to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
def tail_path
|
52
|
+
Pathname.new(ancestry_path).sub_ext('.rb')
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
require_relative './semantic/plain'
|