umwelt 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hanami/interactor'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module Umwelt::Abstract::File
|
7
|
+
class Restore
|
8
|
+
include Hanami::Interactor
|
9
|
+
|
10
|
+
expose :struct
|
11
|
+
|
12
|
+
def initialize(path: '.umwelt',
|
13
|
+
mapper: Struct)
|
14
|
+
@path = path
|
15
|
+
@mapper = mapper
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def read(path)
|
21
|
+
path.read
|
22
|
+
rescue Errno::ENOENT
|
23
|
+
error! "Failed reading #{path}"
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(str)
|
27
|
+
JSON.parse(str, symbolize_names: true)
|
28
|
+
rescue JSON::ParserError
|
29
|
+
error! "Failed JSON parsing #{self.class.name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
def struct(struct_hash)
|
33
|
+
clean @mapper.new.call(struct_hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
def clean(result)
|
37
|
+
if result.success?
|
38
|
+
result.struct
|
39
|
+
else
|
40
|
+
error! result.errors
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def umwelt_root_path
|
45
|
+
Pathname.pwd / @path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hanami/interactor'
|
4
|
+
require 'json'
|
5
|
+
require 'fileutils'
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
module Umwelt::Abstract::File
|
9
|
+
class Store
|
10
|
+
extend Forwardable
|
11
|
+
include Hanami::Interactor
|
12
|
+
def_delegators FileUtils, :mkpath
|
13
|
+
|
14
|
+
def initialize(path: '.umwelt')
|
15
|
+
@path = path
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def serialize(struct)
|
21
|
+
JSON.pretty_generate struct
|
22
|
+
end
|
23
|
+
|
24
|
+
def destruct(obj)
|
25
|
+
obj.is_a?(Struct) ? destruct_members(obj.to_h) : obj
|
26
|
+
end
|
27
|
+
|
28
|
+
def destruct_members(hash)
|
29
|
+
hash.transform_values do |value|
|
30
|
+
if value.is_a?(Array)
|
31
|
+
value.map { |member| destruct(member) }
|
32
|
+
elsif value.is_a? Time
|
33
|
+
value.to_s
|
34
|
+
else
|
35
|
+
destruct(value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def umwelt_root_path
|
41
|
+
Pathname.pwd / @path
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hanami/interactor'
|
4
|
+
# require_relative './structs/phase'
|
5
|
+
# require_relative './structs/fragment'
|
6
|
+
|
7
|
+
class Umwelt::Abstract::Mapper
|
8
|
+
include Hanami::Interactor
|
9
|
+
|
10
|
+
expose :struct
|
11
|
+
|
12
|
+
def fill(struct, data)
|
13
|
+
struct.new(data)
|
14
|
+
rescue ArgumentError => e
|
15
|
+
error! [self.class.name, e.message, data]
|
16
|
+
end
|
17
|
+
end
|
data/lib/umwelt/cli.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::CLI::Commands
|
4
|
+
require_relative './commands/convey'
|
5
|
+
require_relative './commands/clone'
|
6
|
+
require_relative './commands/pull'
|
7
|
+
require_relative './commands/version'
|
8
|
+
|
9
|
+
extend Hanami::CLI::Registry
|
10
|
+
|
11
|
+
register 'convey', Convey
|
12
|
+
register 'clone', Clone
|
13
|
+
register 'pull', Pull
|
14
|
+
register 'version', Version
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::CLI
|
4
|
+
class Commands::Clone < Hanami::CLI::Command
|
5
|
+
desc 'Clone project from remote Umwelt'
|
6
|
+
|
7
|
+
argument :project,
|
8
|
+
type: :string, required: true,
|
9
|
+
desc: 'provide project as USERNAME/PROJECTNAME'
|
10
|
+
|
11
|
+
def call(project:)
|
12
|
+
puts "Cloning project: <#{project}>"
|
13
|
+
# Generator::Element.new(element).create
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::CLI::Commands
|
4
|
+
class Convey < Hanami::CLI::Command
|
5
|
+
extend Forwardable
|
6
|
+
def_delegators Hanami::Utils::String, :classify
|
7
|
+
|
8
|
+
desc 'Convey Phase in Semantic from local Umwelt'
|
9
|
+
|
10
|
+
argument :phase,
|
11
|
+
type: :integer,
|
12
|
+
required: true,
|
13
|
+
desc: 'provide PHASE_ID to imprint'
|
14
|
+
|
15
|
+
argument :semantic,
|
16
|
+
type: :string,
|
17
|
+
default: 'plain',
|
18
|
+
values: %w[plain],
|
19
|
+
required: true,
|
20
|
+
desc: 'provide SEMANTIC to imprint'
|
21
|
+
|
22
|
+
option :source,
|
23
|
+
type: :string,
|
24
|
+
default: '.umwelt',
|
25
|
+
desc: 'provide folder where source stored'
|
26
|
+
|
27
|
+
option :target,
|
28
|
+
type: :string,
|
29
|
+
default: 'umwelt',
|
30
|
+
desc: 'provide folder for imprint'
|
31
|
+
|
32
|
+
def call(phase:, semantic:, **options)
|
33
|
+
puts "Buildung phase: #{phase} with semantic #{semantic}..."
|
34
|
+
|
35
|
+
if phase.to_i.zero?
|
36
|
+
puts 'Error: Phase must be an integer'
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
@convey = Umwelt::Command::Convey.new.call(
|
41
|
+
phase_id: phase.to_i,
|
42
|
+
semantic: classify(semantic).to_sym,
|
43
|
+
source: Pathname.new(options.fetch(:source)),
|
44
|
+
target: Pathname.new(options.fetch(:target))
|
45
|
+
)
|
46
|
+
|
47
|
+
if @convey.success?
|
48
|
+
@convey.result.each_pair do |key, value|
|
49
|
+
puts "#{key} => (#{value})"
|
50
|
+
end
|
51
|
+
puts "#{@convey.result.keys.count} files written succesfully"
|
52
|
+
else
|
53
|
+
@convey.errors.each { |e| puts "Error: #{e}" }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::Command
|
4
|
+
class Convey
|
5
|
+
include Hanami::Interactor
|
6
|
+
# TODO: change to dry-rb transaction here
|
7
|
+
|
8
|
+
expose :result
|
9
|
+
|
10
|
+
def call(phase_id:, semantic:, source:, target:)
|
11
|
+
@result = imprint(
|
12
|
+
tree(source, phase_id), target, semantic
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def tree(source, phase_id)
|
19
|
+
tree_fill(
|
20
|
+
aggregate_history(
|
21
|
+
follow_history(
|
22
|
+
trace_history(
|
23
|
+
restore_history(source),
|
24
|
+
phase_id
|
25
|
+
), source
|
26
|
+
)
|
27
|
+
)
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def imprint(tree, target, semantic)
|
32
|
+
result = Umwelt::Tree::Imprint.new(tree, location: target).call(semantic)
|
33
|
+
if result.success?
|
34
|
+
result.written_paths
|
35
|
+
else
|
36
|
+
error! result.errors
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def tree_fill(fragments)
|
41
|
+
Umwelt::Tree::Fill.new.call(fragments)
|
42
|
+
end
|
43
|
+
|
44
|
+
def aggregate_history(episodes)
|
45
|
+
result = Umwelt::History::Aggregate.new.call(episodes)
|
46
|
+
if result.success?
|
47
|
+
result.fragments
|
48
|
+
else
|
49
|
+
error! result.errors
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def follow_history(continuity, source)
|
54
|
+
result = Umwelt::History::Follow
|
55
|
+
.new(path: source)
|
56
|
+
.call(continuity)
|
57
|
+
if result.success?
|
58
|
+
result.episodes
|
59
|
+
else
|
60
|
+
error! result.errors
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def trace_history(history, phase_id)
|
65
|
+
result = Umwelt::History::Trace.new.call(history, phase_id)
|
66
|
+
if result.success?
|
67
|
+
result.continuity
|
68
|
+
else
|
69
|
+
error! result.errors
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def restore_history(source)
|
74
|
+
restored = Umwelt::History::File::Restore
|
75
|
+
.new(path: source)
|
76
|
+
.call
|
77
|
+
if restored.success?
|
78
|
+
restored.struct
|
79
|
+
else
|
80
|
+
error! "Cannot restore history of #{phase_id}: #{restored.errors}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../structs/episode'
|
4
|
+
|
5
|
+
module Umwelt::Episode::File
|
6
|
+
class Restore < Umwelt::Abstract::File::Restore
|
7
|
+
def initialize(
|
8
|
+
path: '.umwelt',
|
9
|
+
mapper: Umwelt::Episode::Mapper
|
10
|
+
)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(phase_id)
|
15
|
+
@struct = struct parse read full_path phase_id
|
16
|
+
end
|
17
|
+
|
18
|
+
def full_path(phase_id)
|
19
|
+
umwelt_root_path / "episodes/#{phase_id}.json"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Umwelt::Episode::File
|
4
|
+
class Store < Umwelt::Abstract::File::Store
|
5
|
+
def call(id, struct)
|
6
|
+
mkpath full_path(id).dirname
|
7
|
+
|
8
|
+
full_path(id).write serialize(destruct(struct))
|
9
|
+
end
|
10
|
+
|
11
|
+
def full_path(id)
|
12
|
+
umwelt_root_path / "episodes/#{id}.json"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../structs/phase'
|
4
|
+
require_relative '../structs/fragment'
|
5
|
+
|
6
|
+
module Umwelt::Episode
|
7
|
+
class Mapper < Umwelt::Abstract::Mapper
|
8
|
+
def call(
|
9
|
+
data = {
|
10
|
+
phase: {},
|
11
|
+
engaged: [],
|
12
|
+
forgotten: []
|
13
|
+
}
|
14
|
+
)
|
15
|
+
|
16
|
+
@struct = Struct::Episode.new(
|
17
|
+
phase: phase(data[:phase]),
|
18
|
+
engaged: fragments(data[:engaged]),
|
19
|
+
forgotten: data[:forgotten]
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def fragments(array)
|
26
|
+
array.map { |data| fill(Struct::Fragment, data) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def phase(data)
|
30
|
+
fill(Struct::Phase, data)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|