alki 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.adoc +108 -6
  3. data/alki.gemspec +2 -2
  4. data/bin/alki +17 -0
  5. data/config/dsls.rb +2 -2
  6. data/doc/assembly_dsl.adoc +6 -6
  7. data/exe/alki +275 -0
  8. data/lib/alki/assembly/builder.rb +113 -0
  9. data/lib/alki/assembly/executor.rb +127 -0
  10. data/lib/alki/assembly/handler_base.rb +21 -0
  11. data/lib/alki/assembly/instance.rb +21 -0
  12. data/lib/alki/assembly/types/assembly.rb +92 -0
  13. data/lib/alki/assembly/types/factory.rb +29 -0
  14. data/lib/alki/assembly/types/func.rb +12 -0
  15. data/lib/alki/assembly/types/group.rb +39 -0
  16. data/lib/alki/assembly/types/override.rb +40 -0
  17. data/lib/alki/assembly/types/proc_value.rb +18 -0
  18. data/lib/alki/assembly/types/service.rb +27 -0
  19. data/lib/alki/assembly/types/value.rb +9 -0
  20. data/lib/alki/assembly.rb +21 -40
  21. data/lib/alki/dsls/assembly.rb +10 -12
  22. data/lib/alki/dsls/assembly_group.rb +92 -0
  23. data/lib/alki/dsls/assembly_type.rb +5 -15
  24. data/lib/alki/execution/cache_entry.rb +16 -0
  25. data/lib/alki/execution/context.rb +29 -0
  26. data/lib/alki/execution/context_class_builder.rb +36 -0
  27. data/lib/alki/execution/value_context.rb +14 -0
  28. data/lib/alki/overlay_delegator.rb +8 -20
  29. data/lib/alki/overlay_info.rb +3 -0
  30. data/lib/alki/override_builder.rb +6 -4
  31. data/lib/alki/service_delegator.rb +3 -3
  32. data/lib/alki/version.rb +1 -1
  33. data/lib/alki.rb +4 -4
  34. data/test/feature/alki_test.rb +1 -2
  35. data/test/feature/example_test.rb +2 -3
  36. data/test/feature/factories_test.rb +48 -0
  37. data/test/feature/overlays_test.rb +225 -0
  38. data/test/feature/overrides_test.rb +1 -2
  39. data/test/feature/pseudo_elements_test.rb +67 -0
  40. data/test/feature_test_helper.rb +1 -0
  41. data/test/fixtures/example/config/assembly.rb +11 -2
  42. data/test/fixtures/example/config/handlers.rb +2 -7
  43. data/test/fixtures/example/lib/log_overlay.rb +3 -3
  44. data/test/integration/dsls/assembly_test.rb +3 -8
  45. data/test/integration/dsls/assembly_type_test.rb +2 -2
  46. data/test/integration/dsls/service_dsl_test.rb +2 -2
  47. metadata +36 -18
  48. data/lib/alki/assembly_builder.rb +0 -109
  49. data/lib/alki/assembly_executor.rb +0 -129
  50. data/lib/alki/assembly_handler_base.rb +0 -19
  51. data/lib/alki/dsls/assembly_type_dsl.rb +0 -21
  52. data/lib/alki/dsls/assembly_types/assembly.rb +0 -101
  53. data/lib/alki/dsls/assembly_types/group.rb +0 -41
  54. data/lib/alki/dsls/assembly_types/load.rb +0 -31
  55. data/lib/alki/dsls/assembly_types/overlay.rb +0 -9
  56. data/lib/alki/dsls/assembly_types/value.rb +0 -100
  57. data/test/test_helper.rb +0 -1
@@ -0,0 +1,16 @@
1
+ module Alki
2
+ module Execution
3
+ class CacheEntry
4
+ attr_accessor :type,:value,:status
5
+ def initialize
6
+ @status = :building
7
+ end
8
+
9
+ def finish(type,value)
10
+ @status = :done
11
+ @type = type
12
+ @value = value
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ require 'alki/service_delegator'
2
+
3
+ module Alki
4
+ module Execution
5
+ module Context
6
+ def lookup(*path)
7
+ path.flatten.inject(self) do |group,elem|
8
+ unless elem.is_a?(String) or elem.is_a?(Symbol)
9
+ raise ArgumentError.new("lookup can only take Strings or Symbols")
10
+ end
11
+ elem.to_s.split('.').inject(group) do |group,name|
12
+ raise "Invalid lookup elem" unless group.is_a? Context
13
+ group.send name.to_sym
14
+ end
15
+ end
16
+ end
17
+
18
+ def lazy(*path)
19
+ path = path.flatten.inject('') do |path,elem|
20
+ unless elem.is_a?(String) or elem.is_a?(Symbol)
21
+ raise ArgumentError.new("lookup can only take Strings or Symbols")
22
+ end
23
+ path << elem.to_s
24
+ end
25
+ Alki::ServiceDelegator.new self, path
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,36 @@
1
+ require 'alki/class_builder'
2
+
3
+ module Alki
4
+ module Execution
5
+ module ContextClassBuilder
6
+ def self.build(config)
7
+ if config[:body]
8
+ methods = {
9
+ __call__: {body: (config[:body])},
10
+ meta: {body: ->{@__meta__}}
11
+ }
12
+ else
13
+ methods = {}
14
+ end
15
+ (config[:scope]||{}).each do |name,path|
16
+ methods[name] = {
17
+ body:->(*args,&blk) {
18
+ @__executor__.execute @__meta__, path, args, blk
19
+ }
20
+ }
21
+ end
22
+ (config[:methods]||{}).each do |name,body|
23
+ methods[name] = {
24
+ body: body,
25
+ private: true,
26
+ }
27
+ end
28
+ ClassBuilder.build(
29
+ initialize_params: [:__executor__,:__meta__],
30
+ modules: config[:modules],
31
+ instance_methods: methods,
32
+ )
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ require 'alki/execution/context'
2
+ require 'alki/overlay_delegator'
3
+
4
+ module Alki
5
+ module Execution
6
+ module ValueContext
7
+ include Context
8
+
9
+ def delegate_overlay(obj,overlay,**args)
10
+ Alki::OverlayDelegator.new(obj,overlay,args)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -1,33 +1,21 @@
1
1
  module Alki
2
2
  class OverlayDelegator
3
- def initialize(name,obj,overlay)
4
- @name = name
3
+ def initialize(obj,overlay,info=nil)
5
4
  @obj = obj
6
5
  @overlay = overlay
7
- @key = :"#{obj.object_id}:#{overlay.object_id}"
6
+ @info = info
8
7
  end
9
8
 
10
9
  def respond_to_missing(method,include_private = false)
11
- unless Thread.current[@key]
12
- Thread.current[@key] = true
13
- if @overlay.respond_to? :overlay_respond_to?
14
- @overlay.overlay_respond_to? @obj, method, include_private
15
- else
16
- @obj.respond_to? method, include_private
17
- end
18
- Thread.current[@key] = false
10
+ if @overlay.respond_to? :overlay_respond_to?
11
+ @overlay.overlay_respond_to? @obj, method, include_private
12
+ else
13
+ @obj.respond_to? method, include_private
19
14
  end
20
15
  end
21
16
 
22
17
  def method_missing(method,*args,&blk)
23
- if Thread.current[@key]
24
- res = @obj.send method, *args, &blk
25
- else
26
- Thread.current[@key] = true
27
- res = @overlay.overlay_send @name, @obj, method, *args, &blk
28
- Thread.current[@key] = false
29
- end
30
- res
18
+ @overlay.overlay_send @obj, @info, method, *args, &blk
31
19
  end
32
20
  end
33
- end
21
+ end
@@ -0,0 +1,3 @@
1
+ module Alki
2
+ OverlayInfo = Struct.new(:target,:overlay,:args)
3
+ end
@@ -4,9 +4,11 @@ module Alki
4
4
  module OverrideBuilder
5
5
  def self.build(override_hash=nil,&blk)
6
6
  if blk
7
- Alki::Dsls::Assembly.build(&blk)[:root]
7
+ Alki::Dsls::AssemblyGroup.build(&blk)
8
8
  elsif override_hash && !override_hash.empty?
9
- create_override_group override_hash
9
+ { root: create_override_group(override_hash), overlays: [] }
10
+ else
11
+ { root: nil, overlays: [] }
10
12
  end
11
13
  end
12
14
 
@@ -28,8 +30,8 @@ module Alki
28
30
  end
29
31
 
30
32
  def self.build_type(type,*args)
31
- Alki::Support.load_class("alki/assembly_types/#{type}").new *args
33
+ Alki::Support.load_class("alki/assembly/types/#{type}").new *args
32
34
  end
33
35
 
34
36
  end
35
- end
37
+ end
@@ -2,13 +2,13 @@ require 'delegate'
2
2
 
3
3
  module Alki
4
4
  class ServiceDelegator < Delegator
5
- def initialize(app,path)
6
- @app = app
5
+ def initialize(elem,path)
6
+ @elem = elem
7
7
  @path = path
8
8
  end
9
9
 
10
10
  def __getobj__
11
- @obj ||= @app.lookup(@path)
11
+ @obj ||= @elem.lookup(@path)
12
12
  end
13
13
  end
14
14
  end
data/lib/alki/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Alki
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.0"
3
3
  end
data/lib/alki.rb CHANGED
@@ -1,17 +1,17 @@
1
1
  require 'alki/dsl'
2
- require 'alki/assembly_builder'
2
+ require 'alki/assembly/builder'
3
3
 
4
4
  module Alki
5
5
  class << self
6
6
  def project_assembly!(opts={},&blk)
7
7
  opts[:project_assembly] ||= caller_locations(1,1)[0].absolute_path
8
- AssemblyBuilder.build(opts,&blk)
8
+ Assembly::Builder.build(opts,&blk)
9
9
  end
10
10
 
11
11
  alias_method :create_assembly!, :project_assembly!
12
12
 
13
13
  def create_assembly(opts={},&blk)
14
- AssemblyBuilder.build(opts,&blk)
14
+ Assembly::Builder.build(opts,&blk)
15
15
  end
16
16
  end
17
- end
17
+ end
@@ -1,5 +1,4 @@
1
- require_relative '../test_helper'
2
- require 'alki'
1
+ require 'alki/feature_test'
3
2
 
4
3
  describe Alki do
5
4
  describe :create_assembly do
@@ -1,5 +1,4 @@
1
- require_relative '../test_helper'
2
-
1
+ require 'alki/test'
3
2
 
4
3
  $LOAD_PATH.unshift Alki::Test.fixture_path('example','lib')
5
4
  $LOAD_PATH.unshift Alki::Test.fixture_path('tlogger','lib')
@@ -46,4 +45,4 @@ describe 'Example' do
46
45
  it 'should have config_dir value' do
47
46
  Example.new.config_dir.must_equal Alki::Test.fixture_path('example','config')
48
47
  end
49
- end
48
+ end
@@ -0,0 +1,48 @@
1
+ require 'alki/feature_test'
2
+
3
+ describe 'Factories' do
4
+ def assembly(&blk)
5
+ @assembly = Alki.create_assembly(&blk)
6
+ end
7
+
8
+ def obj
9
+ @obj ||= @assembly.new
10
+ end
11
+
12
+ it 'should call returned callable when referenced' do
13
+ assembly do
14
+ factory :test do
15
+ -> (val) { val + 1 }
16
+ end
17
+ end
18
+ obj.test(1).must_equal 2
19
+ end
20
+
21
+ it 'should evaluate the given block once' do
22
+ counter = 0
23
+ proc_counter = 0
24
+ assembly do
25
+ factory :test do
26
+ counter += 1
27
+ -> (val) {
28
+ proc_counter += 1
29
+ val
30
+ }
31
+ end
32
+ end
33
+ obj.test(1)
34
+ obj.test(1)
35
+ counter.must_equal 1
36
+ proc_counter.must_equal 2
37
+ end
38
+
39
+ it 'should return Proc of factory if no arguments are provided when referenced' do
40
+ assembly do
41
+ factory :test do
42
+ -> (val) { val + 1 }
43
+ end
44
+ end
45
+ proc = obj.test
46
+ proc.call(1).must_equal 2
47
+ end
48
+ end
@@ -0,0 +1,225 @@
1
+ require 'alki/feature_test'
2
+
3
+ describe 'Overlays' do
4
+ it 'should allow setting an overlay on a service' do
5
+ values = []
6
+ assembly = Alki.create_assembly do
7
+ service :svc do
8
+ :test
9
+ end
10
+
11
+ overlay :svc, :test_overlay
12
+
13
+ set :test_overlay, ->(value) {values << value; :transformed}
14
+ end
15
+ assembly.new.svc.must_equal :transformed
16
+ values.must_equal [:test]
17
+ end
18
+
19
+ it 'should call new if overlay responds to it' do
20
+ assembly = Alki.create_assembly do
21
+ service :svc do
22
+ :test
23
+ end
24
+
25
+ overlay :svc, :test_overlay
26
+
27
+ set :test_overlay, Struct.new(:val)
28
+ end
29
+ assembly.new.svc.val.must_equal :test
30
+ end
31
+
32
+ it 'should allow using factories as overlays' do
33
+ values = []
34
+ assembly = Alki.create_assembly do
35
+ service :svc do
36
+ :test
37
+ end
38
+
39
+ overlay :svc, :test_overlay
40
+
41
+ factory :test_overlay do
42
+ ->(value) {values << value; :transformed}
43
+ end
44
+ end
45
+ assembly.new.svc.must_equal :transformed
46
+ values.must_equal [:test]
47
+ end
48
+
49
+ it 'should allow setting an overlay on groups of services' do
50
+ values = []
51
+ assembly = Alki.create_assembly do
52
+ service :svc do
53
+ :test
54
+ end
55
+
56
+ group :svcs do
57
+ service :one do
58
+ :svc_one
59
+ end
60
+
61
+ service :two do
62
+ :svc_two
63
+ end
64
+ end
65
+
66
+ overlay :svcs, :test_overlay
67
+
68
+ set :test_overlay, ->(value) {values << value; "overlay_#{value}".to_sym}
69
+ end
70
+ obj = assembly.new
71
+ obj.svc.must_equal :test
72
+ obj.svcs.one.must_equal :overlay_svc_one
73
+ obj.svcs.two.must_equal :overlay_svc_two
74
+ values.must_equal [:svc_one,:svc_two]
75
+ end
76
+
77
+ it 'should not apply to non-services' do
78
+ values = []
79
+ assembly = Alki.create_assembly do
80
+ group :vals do
81
+ set :one do
82
+ :val_one
83
+ end
84
+
85
+ factory :two do
86
+ ->(v) { "val_two_#{v}".to_sym }
87
+ end
88
+
89
+ func :three do
90
+ :val_three
91
+ end
92
+ end
93
+
94
+ overlay :vals, :test_overlay
95
+
96
+ set :test_overlay, ->(value) {values << value; "overlay_#{value}".to_sym}
97
+ end
98
+ obj = assembly.new
99
+ obj.vals.one.must_equal :val_one
100
+ obj.vals.two(1).must_equal :val_two_1
101
+ obj.vals.three.must_equal :val_three
102
+ values.must_equal []
103
+ end
104
+
105
+ it 'should chain overlays when multiple are set' do
106
+ values = []
107
+ assembly = Alki.create_assembly do
108
+
109
+ group :svcs do
110
+ service :svc do
111
+ :test
112
+ end
113
+ end
114
+
115
+ overlay :svcs, :overlay1
116
+ overlay 'svcs.svc', :overlay2
117
+
118
+ set :overlay1, ->(value) {values << value; "overlay_#{value}".to_sym}
119
+ set :overlay2, ->(value) {values << value; :transformed}
120
+
121
+ end
122
+ obj = assembly.new
123
+ obj.svcs.svc.must_equal :transformed
124
+ values.must_equal [:test,:overlay_test]
125
+ end
126
+
127
+ it 'should follow paths when setting overlay targets' do
128
+ values = []
129
+ assembly = Alki.create_assembly do
130
+ service :svc do
131
+ :test
132
+ end
133
+
134
+ group :grp do
135
+ overlay 'assembly.svc', :test_overlay
136
+
137
+ set :test_overlay, ->(value) {values << value; :transformed}
138
+ end
139
+ end
140
+ obj = assembly.new
141
+ obj.svc.must_equal :transformed
142
+ values.must_equal [:test]
143
+ end
144
+
145
+ it 'should raise error if either target or overlay paths are invalid' do
146
+ assembly = Alki.create_assembly do
147
+ service :svc do
148
+ :test
149
+ end
150
+ overlay :invalid, :test_overlay
151
+ set :test_overlay, ->(value) {:child}
152
+ end
153
+ assert_raises Alki::InvalidPathError do
154
+ assembly.new.svc
155
+ end
156
+ assembly = Alki.create_assembly do
157
+ service :svc do
158
+ :test
159
+ end
160
+ overlay :svc, :invalid
161
+ end
162
+ assert_raises Alki::InvalidPathError do
163
+ assembly.new.svc
164
+ end
165
+ end
166
+
167
+ it 'should set overlays through mounted assemblies' do
168
+ child = Alki.create_assembly do
169
+ service :svc do
170
+ :test
171
+ end
172
+ overlay 'parent.svc', :test_overlay
173
+ set :test_overlay, ->(value) {:child}
174
+ end
175
+ assembly = Alki.create_assembly do
176
+ service :svc do
177
+ :test
178
+ end
179
+ mount :mounted, child
180
+ overlay 'mounted.svc', :test_overlay
181
+ set :test_overlay, ->(value) {:parent}
182
+ end
183
+ obj = assembly.new
184
+ obj.svc.must_equal :child
185
+ obj.mounted.svc.must_equal :parent
186
+ end
187
+
188
+ it 'should set overlays from overrides' do
189
+ child = Alki.create_assembly do
190
+ service :svc1 do
191
+ :test
192
+ end
193
+ end
194
+ assembly = Alki.create_assembly do
195
+ service :svc2 do
196
+ :test
197
+ end
198
+ mount :mounted, child do
199
+ overlay 'original.svc1', :test_overlay
200
+ set :test_overlay, ->(value) {:parent}
201
+ end
202
+ end
203
+ obj = assembly.new do
204
+ overlay 'original.svc2', :test_overlay
205
+ set :test_overlay, ->(value) {:child}
206
+ end
207
+ obj.svc2.must_equal :child
208
+ obj.mounted.svc1.must_equal :parent
209
+ end
210
+
211
+ it 'should allow setting overlays on assembly_instance' do
212
+ values = []
213
+ assembly = Alki.create_assembly do
214
+ overlay :assembly_instance, :test_overlay
215
+
216
+ set :test_overlay, ->(value) {
217
+ values << value
218
+ :transformed
219
+ }
220
+ end
221
+ assembly.new.must_equal :transformed
222
+ values.size.must_equal 1
223
+ values[0].must_be_instance_of Alki::Assembly::Instance
224
+ end
225
+ end
@@ -1,6 +1,5 @@
1
- require_relative '../test_helper'
1
+ require 'alki/feature_test'
2
2
  require 'logger'
3
- require 'alki'
4
3
  require 'stringio'
5
4
 
6
5
  describe 'Overrides' do
@@ -0,0 +1,67 @@
1
+ require 'alki/feature_test'
2
+
3
+ describe 'Pseudo Elements' do
4
+ before do
5
+ @config_dir = fixture_path('example','config')
6
+ two = Alki.create_assembly do
7
+ set :num, 2
8
+ set :assembly_num do
9
+ assembly.num
10
+ end
11
+ set :parent_num do
12
+ parent.num
13
+ end
14
+ set :grandparent_num do
15
+ parent.parent.num
16
+ end
17
+ set :root_num do
18
+ root.num
19
+ end
20
+ end
21
+ one = Alki.create_assembly do
22
+ mount :two, two
23
+ set :num, 1
24
+ end
25
+ zero = Alki.create_assembly(config_dir: @config_dir) do
26
+ mount :one, one
27
+ set :num, 0
28
+ set :has_parent do
29
+ respond_to?(:parent)
30
+ end
31
+ end
32
+ @assembly = zero
33
+ @obj = @assembly.new
34
+ end
35
+
36
+ describe 'assembly' do
37
+ it 'should be the local assembly of the referring element' do
38
+ @obj.one.two.assembly_num.must_equal 2
39
+ end
40
+ end
41
+
42
+ describe 'parent' do
43
+ it 'should be the parent assembly of the referring element' do
44
+ @obj.one.two.parent_num.must_equal 1
45
+ end
46
+
47
+ it 'should be attribute on all assemblies with parents' do
48
+ @obj.one.two.grandparent_num.must_equal 0
49
+ end
50
+
51
+ it 'should only exist if assembly has parent' do
52
+ @obj.has_parent.must_equal false
53
+ end
54
+ end
55
+
56
+ describe 'root' do
57
+ it 'should be the root assembly' do
58
+ @obj.one.two.root_num.must_equal 0
59
+ end
60
+ end
61
+
62
+ describe 'config_dir' do
63
+ it 'should be the config_dir setting set in the assembly when it was created' do
64
+ @obj.config_dir.must_equal @config_dir
65
+ end
66
+ end
67
+ end
@@ -0,0 +1 @@
1
+ require 'alki'
@@ -2,6 +2,15 @@ Alki do
2
2
  load :settings
3
3
  load :handlers
4
4
 
5
+ factory :log_overlay do
6
+ require 'log_overlay'
7
+ -> (obj) {
8
+ delegate_overlay obj, LogOverlay.new(log), name: meta[:building]
9
+ }
10
+ end
11
+
12
+ overlay :handlers, :log_overlay
13
+
5
14
  service :handler do
6
15
  require 'switch_handler'
7
16
  SwitchHandler.new [
@@ -31,7 +40,7 @@ Alki do
31
40
  StringIO.new
32
41
  end
33
42
 
34
- assembly :tlogger do
43
+ mount :tlogger do
35
44
  set :io do
36
45
  log_io
37
46
  end
@@ -46,4 +55,4 @@ Alki do
46
55
  msg[0].upcase+msg[1..-1].downcase+"!"
47
56
  }
48
57
  end
49
- end
58
+ end
@@ -2,7 +2,7 @@ Alki do
2
2
  factory :num_handler do
3
3
  require 'num_handler'
4
4
  -> (num,str) {
5
- NumHandler.new num, str, output
5
+ NumHandler.new(num, str, output)
6
6
  }
7
7
  end
8
8
 
@@ -22,9 +22,4 @@ Alki do
22
22
  require 'echo_handler'
23
23
  EchoHandler.new output
24
24
  end
25
-
26
- overlay do
27
- require 'log_overlay'
28
- LogOverlay.new lookup('log')
29
- end
30
- end
25
+ end
@@ -3,8 +3,8 @@ class LogOverlay
3
3
  @log = log
4
4
  end
5
5
 
6
- def overlay_send(name,obj,method,*args,&blk)
7
- @log << "Calling #{name}##{method} #{args.join(", ")}\n"
6
+ def overlay_send(obj,info,method,*args,&blk)
7
+ @log << "Calling #{info[:name]}##{method} #{args.join(", ")}\n"
8
8
  obj.public_send method, *args, &blk
9
9
  end
10
- end
10
+ end
@@ -1,25 +1,20 @@
1
- require_relative '../../test_helper'
1
+ require 'alki/test'
2
2
  require 'alki/dsls/assembly'
3
3
 
4
4
  describe Alki::Dsls::Assembly do
5
- it 'should work' do
5
+ it 'should allow creating Assembly config classes' do
6
6
  res = Alki::Dsls::Assembly.build do
7
7
  service :test do
8
8
  :val
9
9
  end
10
10
 
11
- load 'file'
12
-
13
11
  group :group1 do
14
12
  service :test2 do
15
13
  :val2
16
14
  end
17
15
  end
18
16
  end
19
- res[:class].root.children[:file].name.must_equal 'file'
20
17
  res[:class].root.children[:test].must_respond_to :block
21
18
  res[:class].root.children[:group1].children[:test2].must_respond_to :block
22
-
23
- r = res[:class].root.lookup [:group1,:test2]
24
19
  end
25
- end
20
+ end