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.
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'