umwelt 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +46 -0
  3. data/.gitignore +8 -0
  4. data/.rubocop.yml +28 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +7 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +8 -0
  10. data/Gemfile.lock +79 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +75 -0
  13. data/Rakefile +12 -0
  14. data/bin/console +14 -0
  15. data/bin/setup +8 -0
  16. data/bin/umwelt +7 -0
  17. data/lib/umwelt.rb +23 -0
  18. data/lib/umwelt/abstract.rb +7 -0
  19. data/lib/umwelt/abstract/file.rb +7 -0
  20. data/lib/umwelt/abstract/file/restore.rb +48 -0
  21. data/lib/umwelt/abstract/file/store.rb +44 -0
  22. data/lib/umwelt/abstract/mapper.rb +17 -0
  23. data/lib/umwelt/cli.rb +6 -0
  24. data/lib/umwelt/cli/commands.rb +15 -0
  25. data/lib/umwelt/cli/commands/clone.rb +16 -0
  26. data/lib/umwelt/cli/commands/convey.rb +57 -0
  27. data/lib/umwelt/cli/commands/pull.rb +11 -0
  28. data/lib/umwelt/cli/commands/version.rb +9 -0
  29. data/lib/umwelt/command.rb +6 -0
  30. data/lib/umwelt/command/convey.rb +84 -0
  31. data/lib/umwelt/episode.rb +7 -0
  32. data/lib/umwelt/episode/file.rb +7 -0
  33. data/lib/umwelt/episode/file/restore.rb +22 -0
  34. data/lib/umwelt/episode/file/store.rb +15 -0
  35. data/lib/umwelt/episode/mapper.rb +33 -0
  36. data/lib/umwelt/fragment.rb +6 -0
  37. data/lib/umwelt/fragment/mapper.rb +11 -0
  38. data/lib/umwelt/history.rb +10 -0
  39. data/lib/umwelt/history/aggregate.rb +49 -0
  40. data/lib/umwelt/history/file.rb +7 -0
  41. data/lib/umwelt/history/file/restore.rb +22 -0
  42. data/lib/umwelt/history/file/store.rb +15 -0
  43. data/lib/umwelt/history/follow.rb +32 -0
  44. data/lib/umwelt/history/mapper.rb +33 -0
  45. data/lib/umwelt/history/trace.rb +51 -0
  46. data/lib/umwelt/node.rb +46 -0
  47. data/lib/umwelt/node/build.rb +31 -0
  48. data/lib/umwelt/node/root.rb +6 -0
  49. data/lib/umwelt/node/space.rb +6 -0
  50. data/lib/umwelt/phase.rb +6 -0
  51. data/lib/umwelt/phase/mapper.rb +18 -0
  52. data/lib/umwelt/project.rb +7 -0
  53. data/lib/umwelt/project/file.rb +7 -0
  54. data/lib/umwelt/project/file/restore.rb +22 -0
  55. data/lib/umwelt/project/file/store.rb +15 -0
  56. data/lib/umwelt/project/mapper.rb +11 -0
  57. data/lib/umwelt/semantic.rb +57 -0
  58. data/lib/umwelt/semantic/plain.rb +12 -0
  59. data/lib/umwelt/semantic/plain/root.rb +13 -0
  60. data/lib/umwelt/semantic/plain/space.rb +13 -0
  61. data/lib/umwelt/structs/episode.rb +9 -0
  62. data/lib/umwelt/structs/fragment.rb +13 -0
  63. data/lib/umwelt/structs/history.rb +3 -0
  64. data/lib/umwelt/structs/node.rb +13 -0
  65. data/lib/umwelt/structs/phase.rb +13 -0
  66. data/lib/umwelt/structs/project.rb +10 -0
  67. data/lib/umwelt/structs/trunk.rb +8 -0
  68. data/lib/umwelt/tree.rb +8 -0
  69. data/lib/umwelt/tree/fill.rb +35 -0
  70. data/lib/umwelt/tree/imprint.rb +53 -0
  71. data/lib/umwelt/tree/trunk.rb +27 -0
  72. data/lib/umwelt/version.rb +5 -0
  73. data/umwelt.gemspec +56 -0
  74. metadata +248 -0
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::Abstract
4
+ end
5
+
6
+ require_relative './abstract/file'
7
+ require_relative './abstract/mapper'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::Abstract::File
4
+ end
5
+
6
+ require_relative './file/store'
7
+ require_relative './file/restore'
@@ -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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::CLI
4
+ end
5
+
6
+ require_relative './cli/commands'
@@ -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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::CLI
4
+ class Commands::Pull < Hanami::CLI::Command
5
+ desc 'Pull project from remote Umwelt'
6
+
7
+ def call(*)
8
+ puts 'Pulling project'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::CLI::Commands
4
+ class Version < Hanami::CLI::Command
5
+ def call(*)
6
+ puts Umwelt::VERSION
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::Command
4
+ end
5
+
6
+ require_relative './command/convey'
@@ -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,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::Episode
4
+ end
5
+
6
+ require_relative './episode/file'
7
+ require_relative './episode/mapper'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::Episode::File
4
+ end
5
+
6
+ require_relative './file/store'
7
+ require_relative './file/restore'
@@ -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
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Umwelt::Fragment
4
+ end
5
+
6
+ require_relative './fragment/mapper'