alki 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +1 -1
  4. data/alki.gemspec +3 -0
  5. data/config/dsls.rb +4 -0
  6. data/lib/alki/assembly.rb +43 -0
  7. data/lib/alki/assembly_executor.rb +137 -0
  8. data/lib/alki/assembly_handler_base.rb +19 -0
  9. data/lib/alki/dsls/assembly.rb +24 -0
  10. data/lib/alki/dsls/assembly_type.rb +48 -0
  11. data/lib/alki/dsls/assembly_type_dsl.rb +21 -0
  12. data/lib/alki/dsls/assembly_types/assembly.rb +84 -0
  13. data/lib/alki/dsls/assembly_types/group.rb +46 -0
  14. data/lib/alki/dsls/assembly_types/load.rb +37 -0
  15. data/lib/alki/dsls/assembly_types/overlay.rb +9 -0
  16. data/lib/alki/dsls/assembly_types/service.rb +25 -0
  17. data/lib/alki/dsls/service.rb +22 -0
  18. data/lib/alki/test.rb +38 -18
  19. data/lib/alki/version.rb +1 -1
  20. data/lib/alki.rb +27 -21
  21. data/test/feature/create_package_test.rb +4 -3
  22. data/test/fixtures/example/config/{package.rb → assembly.rb} +5 -2
  23. data/test/fixtures/example/config/handlers.rb +1 -1
  24. data/test/fixtures/example/lib/example.rb +1 -1
  25. data/test/fixtures/example/lib/switch_handler.rb +2 -2
  26. data/test/fixtures/tlogger/config/assembly.rb +10 -0
  27. data/test/fixtures/tlogger/lib/tlogger.rb +3 -0
  28. data/test/integration/dsls/assembly_test.rb +28 -0
  29. data/test/integration/dsls/assembly_type_test.rb +58 -0
  30. data/test/integration/dsls/service_dsl_test.rb +57 -0
  31. metadata +69 -21
  32. data/lib/alki/class_builder.rb +0 -41
  33. data/lib/alki/dsl_builder.rb +0 -43
  34. data/lib/alki/group_builder.rb +0 -25
  35. data/lib/alki/group_dsl.rb +0 -98
  36. data/lib/alki/loader.rb +0 -32
  37. data/lib/alki/package.rb +0 -33
  38. data/lib/alki/package_builder.rb +0 -2
  39. data/lib/alki/package_executor.rb +0 -120
  40. data/lib/alki/package_processor.rb +0 -167
  41. data/lib/alki/standard_package.rb +0 -19
  42. data/lib/alki/util.rb +0 -35
  43. data/test/integration/class_builder_test.rb +0 -130
  44. data/test/integration/loader_test.rb +0 -36
  45. data/test/unit/package_processor_test.rb +0 -319
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e86bb1b3528f9cb309acbc92afc214435f8a2277
4
- data.tar.gz: a58361e3a16adfdeabfe85f340baef09559250c2
3
+ metadata.gz: af6d088cbc8aa150a26faf3bac734b926bc8904e
4
+ data.tar.gz: faee9dfca16adb81a2d0e4581651ebb7143262eb
5
5
  SHA512:
6
- metadata.gz: de5bc37efcdadd68024bad12dcc29219484888ed31c2d0b09cd634d877ac097696335ff5ac38fbb6fd917ca3b0b35458c4fd18a549e10b967801aa50dfb48989
7
- data.tar.gz: 2e129fbb5b609d32be08ace86498a77183a59ceccf2b60330cf09f77986408484e503f021ce61d5f430ac2f882a2a2c90fb9757bd622b8975cfd5d305cd45dbb
6
+ metadata.gz: f2a8859220bc71ade390e9b66e2c5ea5ae0960763f1aa2c760fff15cb47af76abaa8457a289e70f684f735ba9cab01b0dbdbe64aec5070ab5d62b426b9d4d845
7
+ data.tar.gz: 4f3cfe787245cd977233e33fa3fe01f8555940701e92cb38a732839b0f0006ed5ae314af238aa8bb272c0438193a426539503b322c5b8e05ea2fe454f86cd4eb
data/Gemfile CHANGED
@@ -2,6 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
+ gem 'pry'
6
+
5
7
  group :test do
6
8
  gem 'minitest', '~> 5.4.2'
7
9
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # base.alki
1
+ # Alki
2
2
 
3
3
  Basic library for creating applications.
4
4
 
data/alki.gemspec CHANGED
@@ -21,4 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.add_development_dependency "bundler", "~> 1.6"
23
23
  spec.add_development_dependency "rake", '~> 10.0'
24
+ spec.add_development_dependency "minitest", "~> 5.9"
25
+ spec.add_dependency "alki-dsl", "~> 0.2"
26
+ spec.add_dependency "alki-support", "~> 0.4"
24
27
  end
data/config/dsls.rb ADDED
@@ -0,0 +1,4 @@
1
+ Alki do
2
+ register_lib_dir 'alki/dsls/assembly_types', 'alki/dsls/assembly_type_dsl'
3
+ register_lib_dir 'alki/dsls', 'alki/dsls/dsl'
4
+ end
@@ -0,0 +1,43 @@
1
+ require 'alki/assembly_executor'
2
+
3
+ module Alki
4
+ module Assembly
5
+ def new
6
+ Alki::Assembly::Instance.new assembly, load_path: config_root
7
+ end
8
+
9
+ def assembly
10
+ self.assembly_class.assembly
11
+ end
12
+
13
+ def root
14
+ self.assembly_class.root
15
+ end
16
+
17
+ class Instance
18
+ def initialize(assembly,opts={})
19
+ @assembly = assembly
20
+ @cache = {}
21
+ @opts = opts
22
+ end
23
+
24
+ def root
25
+ @root ||= __executor__.call @assembly, @cache, []
26
+ end
27
+
28
+ def respond_to_missing?(name,include_all)
29
+ root.respond_to? name
30
+ end
31
+
32
+ def method_missing(name,*args,&blk)
33
+ root.send name, *args, &blk
34
+ end
35
+
36
+ private
37
+
38
+ def __executor__
39
+ @executor ||= Alki::AssemblyExecutor.new @opts
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,137 @@
1
+ require 'alki/service_delegator'
2
+ require 'alki/overlay_delegator'
3
+
4
+ module Alki
5
+ class AssemblyExecutor
6
+ class Resource
7
+ attr_reader :pkg, :cache, :elem
8
+ def initialize(pkg,cache,elem)
9
+ @pkg = pkg
10
+ @cache = cache
11
+ @elem = elem
12
+ end
13
+
14
+ def with_elem(elem)
15
+ Resource.new @pkg, @cache, elem
16
+ end
17
+ end
18
+
19
+ def initialize(data={})
20
+ @data = data
21
+ end
22
+
23
+ def call(assembly,cache,path,*args,&blk)
24
+ unless cache[path]
25
+ elem = assembly.lookup path, @data
26
+ raise "Path not found: #{path.join('.')}" unless elem
27
+ res = Resource.new assembly, cache, elem
28
+ cache[path] = case elem[:type]
29
+ when :service
30
+ service res, path
31
+ when :factory
32
+ factory res, &blk
33
+ when :group
34
+ group res
35
+ end
36
+ end
37
+ cache[path].call *args, &blk
38
+ end
39
+
40
+ def service(res,path)
41
+ with_scope_context(res) do |ctx,blk|
42
+ svc = apply_overlays res, path, ctx.instance_exec(&blk)
43
+ -> { svc }
44
+ end
45
+ end
46
+
47
+ def apply_overlays(res,path,obj)
48
+ res.elem[:overlays].inject(obj) do |obj,overlay_elem|
49
+ unless res.cache[overlay_elem[:block]]
50
+ with_scope_context(res.with_elem(overlay_elem)) do |ctx,blk|
51
+ res.cache[overlay_elem[:block]] = ctx.instance_exec(&blk)
52
+ end
53
+ end
54
+ local_path = path[overlay_elem[:scope][:root].size..-1].join('.')
55
+ Alki::OverlayDelegator.new local_path,obj, res.cache[overlay_elem[:block]]
56
+ end
57
+ end
58
+
59
+ def factory(res)
60
+ with_scope_context(res) do |ctx,blk|
61
+ factory = ctx.instance_exec(&blk)
62
+ -> (*args,&blk) {
63
+ if !args.empty? or blk
64
+ factory.call *args, &blk
65
+ else
66
+ factory
67
+ end
68
+ }
69
+ end
70
+ end
71
+
72
+ def group(res)
73
+ proc = -> (name,*args,&blk) {
74
+ call res.pkg, res.cache, res.elem[:scope][name], *args, &blk
75
+ }
76
+ group = GroupContext.new(proc,res.elem[:scope].keys)
77
+ -> { group }
78
+ end
79
+
80
+ def with_scope_context(res)
81
+ proc = -> (name,*args,&blk) {
82
+ call res.pkg, res.cache, res.elem[:scope][name], *args, &blk
83
+ }
84
+
85
+ yield ServiceContext.new(proc,res.elem[:scope].keys), res.elem[:block]
86
+ end
87
+
88
+ class Context
89
+ def initialize(executor,scope)
90
+ @executor = executor
91
+ @scope = scope
92
+ end
93
+
94
+ def respond_to_missing?(name,include_all)
95
+ @scope.include? name
96
+ end
97
+
98
+ def method_missing(name,*args,&blk)
99
+ if @scope.include? name
100
+ @executor.call name, *args, &blk
101
+ else
102
+ super
103
+ end
104
+ end
105
+ end
106
+
107
+ class ServiceContext < Context
108
+ def lookup(path)
109
+ unless path.is_a?(String) or path.is_a?(Symbol)
110
+ raise ArgumentError.new("lookup can only take Strings or Symbols")
111
+ end
112
+ path.to_s.split('.').inject(self) do |group,name|
113
+ raise "Invalid lookup path" unless group.is_a? Context
114
+ group.send name.to_sym
115
+ end
116
+ end
117
+
118
+ def lazy(path)
119
+ unless path.is_a?(String) or path.is_a?(Symbol)
120
+ raise ArgumentError.new("lazy can only take Strings or Symbols")
121
+ end
122
+ Alki::ServiceDelegator.new pkg, path
123
+ end
124
+ end
125
+
126
+ class GroupContext < Context
127
+ def lookup(path)
128
+ unless path.is_a?(String) or path.is_a?(Symbol)
129
+ raise ArgumentError.new("lookup can only take Strings or Symbols")
130
+ end
131
+ path.to_s.split('.').inject(self) do |group,name|
132
+ group.send name.to_sym
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,19 @@
1
+ module Alki
2
+ class AssemblyHandlerBase
3
+ def initialize(elem,data,key=nil)
4
+ @elem = elem
5
+ @data = data
6
+ @key = key
7
+ end
8
+
9
+ attr_reader :elem, :data, :key
10
+
11
+ def index
12
+ raise NotImplementedError.new("Can't index into this element")
13
+ end
14
+
15
+ def output
16
+ raise NotImplementedError.new("Can't output this element")
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ Alki do
2
+ require_dsl 'alki/dsls/class'
3
+ require_dsl 'alki/dsls/assembly_types/group'
4
+ require_dsl 'alki/dsls/assembly_types/load'
5
+ require_dsl 'alki/dsls/assembly_types/service'
6
+ require_dsl 'alki/dsls/assembly_types/assembly'
7
+ require_dsl 'alki/dsls/assembly_types/overlay'
8
+
9
+ init do
10
+ ctx[:elems] = {}
11
+ ctx[:overlays] = []
12
+ end
13
+
14
+ finish do
15
+ root = build_group(ctx[:elems], ctx[:overlays])
16
+ assembly = build_assembly root, nil
17
+ add_class_method :root do
18
+ root
19
+ end
20
+ add_class_method :assembly do
21
+ assembly
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,48 @@
1
+ require 'alki/assembly_handler_base'
2
+
3
+ Alki do
4
+ require_dsl 'alki/dsls/class'
5
+
6
+ init do
7
+ set_super_class Alki::AssemblyHandlerBase, subclass: 'Handler'
8
+
9
+ add_method :handler, private: true do |*args|
10
+ self.class::Handler.new(self,*args)
11
+ end
12
+
13
+ add_method :index do |*args|
14
+ handler(*args).index
15
+ end
16
+
17
+ add_method :output do |*args|
18
+ handler(*args).output
19
+ end
20
+
21
+ add_method :lookup do |path,data={}|
22
+ data = data.dup
23
+ elem = self
24
+ path.each do |key|
25
+ elem = elem.index data, key
26
+ return nil unless elem
27
+ end
28
+ elem.output data
29
+ end
30
+
31
+ # Add defined methods to handler class
32
+ class_builder('Handler')[:module] = class_builder[:module]
33
+ end
34
+
35
+ dsl_method :attr do |name,default=nil|
36
+ add_delegator name, :@elem, subclass: 'Handler'
37
+ add_initialize_param name, default
38
+ add_accessor name
39
+ end
40
+
41
+ dsl_method :index do |&blk|
42
+ add_method :index, subclass: 'Handler', &blk
43
+ end
44
+
45
+ dsl_method :output do |&blk|
46
+ add_method :output, subclass: 'Handler', &blk
47
+ end
48
+ end
@@ -0,0 +1,21 @@
1
+ require 'alki/dsls/assembly_type'
2
+
3
+ Alki do
4
+ require_dsl 'alki/dsls/dsl'
5
+
6
+ dsl_method :element_type do |name,&blk|
7
+ data = Alki::Dsls::AssemblyType.build(prefix: 'alki/assembly_types', name: name,&blk)
8
+ klass = data[:class]
9
+ add_helper "build_#{name}".to_sym, &klass.method(:new)
10
+ add_helper "add_#{name}".to_sym do |name,*args|
11
+ add name, klass.new(*args)
12
+ end
13
+ end
14
+
15
+ finish do
16
+ add_method :add do |name,elem|
17
+ (ctx[:elems]||={})[name.to_sym] = elem
18
+ nil
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,84 @@
1
+ require 'alki/support'
2
+
3
+ Alki do
4
+ require_dsl 'alki/dsls/assembly_types/group'
5
+
6
+ dsl_method :assembly do |name,pkg=name.to_s,&blk|
7
+ klass = Alki::Support.load_class pkg
8
+
9
+ elem = if blk
10
+ build_assembly klass.root, build_group_dsl(blk)
11
+ else
12
+ klass.root
13
+ end
14
+ add name, elem
15
+ end
16
+
17
+ element_type :assembly do
18
+ attr :root
19
+ attr :overrides, nil
20
+
21
+ index do
22
+ if overrides
23
+ data.replace(
24
+ main: data.merge(main_data),
25
+ override: data.dup,
26
+ )
27
+ override.index data, key
28
+ else
29
+ root.index data.merge!(main_data), key
30
+ end
31
+ end
32
+
33
+ output do
34
+ scope = root.output(data)[:scope]
35
+ scope.merge! overrides.output(data)[:scope] if overrides
36
+ {
37
+ type: :group,
38
+ scope: scope,
39
+ }
40
+ end
41
+
42
+ def main_data
43
+ pkg = data[:prefix] ? data[:prefix].dup : []
44
+ {scope: {pkg: pkg, root: []}, overlays: []}
45
+ end
46
+
47
+ def override
48
+ Alki::AssemblyTypes::Override.new root, overrides
49
+ end
50
+ end
51
+
52
+ element_type :override do
53
+ attr :main
54
+ attr :override
55
+
56
+ index do
57
+ main_child = main.index data[:main], key
58
+ override_child = override.index data[:override], key
59
+
60
+ if main_child && override_child
61
+ (data[:main][:scope]||={}).merge! (data[:override][:scope]||{})
62
+ (data[:main][:overlays]||=[]).push *(data[:override][:overlays]||[])
63
+ Alki::AssemblyTypes::Override.new main_child, override_child
64
+ elsif main_child
65
+ data.replace data[:main]
66
+ main_child
67
+ elsif override_child
68
+ data.replace data[:override]
69
+ override_child
70
+ end
71
+ end
72
+
73
+ output do
74
+ result = override.output(data[:override])
75
+ if result[:type] == :group
76
+ main_result = main.output(data[:main])
77
+ if main_result[:type] == :group
78
+ result[:scope] = main_result[:scope].merge result[:scope]
79
+ end
80
+ end
81
+ result
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,46 @@
1
+ require 'alki/dsls/assembly'
2
+
3
+ Alki do
4
+ dsl_method :group do |name,&blk|
5
+ add name, build_group_dsl(blk)
6
+ end
7
+
8
+ helper :build_group_dsl do |blk|
9
+ data = Alki::Dsls::Assembly.build &blk
10
+ build_group data[:elems], data[:overlays]
11
+ end
12
+
13
+ element_type :group do
14
+ attr :children, {}
15
+ attr :overlays
16
+
17
+ index do
18
+ data[:scope] ||= {}
19
+ data[:prefix] ||= []
20
+ update_scope children, data[:prefix], data[:scope]
21
+ data[:prefix] << key
22
+
23
+ if overlays
24
+ data[:overlays] = overlays.map do |o|
25
+ o == :clear ? o : {block: o, scope: data[:scope].merge(root: [])}
26
+ end
27
+ end
28
+
29
+ children[key]
30
+ end
31
+
32
+ output do
33
+ {
34
+ type: :group,
35
+ scope: update_scope(children,data[:prefix]||[],{})
36
+ }
37
+ end
38
+
39
+ def update_scope(children, prefix, scope)
40
+ children.keys.inject(scope) do |h,k|
41
+ h.merge! k => (prefix+[k])
42
+ end
43
+ scope
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,37 @@
1
+ require 'alki/support'
2
+
3
+ Alki do
4
+ dsl_method :load do |group_name,name=group_name.to_s|
5
+ add_load group_name, ctx[:prefix], name
6
+ end
7
+
8
+ element_type :load do
9
+ attr :prefix
10
+ attr :name
11
+
12
+ index do
13
+ group.index data, key
14
+ end
15
+
16
+ output do
17
+ group.output data
18
+ end
19
+
20
+ def group
21
+ unless (data[:loaded]||={})[name]
22
+ if data[:load_path]
23
+ require File.join(data[:load_path],name)
24
+ else
25
+ require name
26
+ end
27
+ prefixed_name = if prefix
28
+ File.join(prefix,name)
29
+ else
30
+ name
31
+ end
32
+ data[:loaded][name] = Alki::Support.load_class(prefixed_name).root
33
+ end
34
+ data[:loaded][name]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,9 @@
1
+ Alki do
2
+ dsl_method :overlay do |&blk|
3
+ (ctx[:overlays]||=[]) << blk
4
+ end
5
+
6
+ dsl_method :clear_overlays do
7
+ (ctx[:overlays]||=[]) << :clear
8
+ end
9
+ end
@@ -0,0 +1,25 @@
1
+ Alki do
2
+ dsl_method :set do |name,value=nil,&blk|
3
+ add_service name, :service, (blk || -> { value })
4
+ end
5
+
6
+ dsl_method :service do |name,&blk|
7
+ add_service name, :service, blk
8
+ end
9
+
10
+ dsl_method :factory do |name,&blk|
11
+ add_service name, :factory, blk
12
+ end
13
+
14
+ element_type :service do
15
+ attr :type
16
+ attr :block
17
+
18
+ output do
19
+ last_clear = data[:overlays].rindex(:clear)
20
+ overlays = last_clear ? data[:overlays][(last_clear + 1)..-1] : data[:overlays]
21
+ scope = data[:scope].merge root: []
22
+ {type: type, block: block, overlays: overlays, scope: scope}
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,22 @@
1
+ Alki do
2
+ require_dsl 'alki/dsls/class'
3
+
4
+ init do
5
+ @uses = []
6
+ end
7
+
8
+ dsl_method :use do |name,service_path = name|
9
+ if name.is_a?(Hash) && name.size == 1
10
+ name, service_path = name.to_a.first
11
+ end
12
+ add_initialize_param name
13
+ @uses << service_path.to_s
14
+ end
15
+
16
+ finish do
17
+ uses = @uses
18
+ add_class_method :uses do
19
+ uses
20
+ end
21
+ end
22
+ end
data/lib/alki/test.rb CHANGED
@@ -1,29 +1,49 @@
1
1
  require 'bundler'
2
2
  Bundler.setup(:default,:test)
3
3
  require 'minitest/autorun'
4
+ require 'alki/dsl'
4
5
 
5
- class Minitest::Spec
6
- def app_root
7
- Bundler.root
8
- end
6
+ module Alki
7
+ module Test
8
+ def app_root
9
+ Bundler.root
10
+ end
9
11
 
10
- def lib_dir
11
- File.join app_root, 'lib'
12
- end
12
+ def lib_dir
13
+ File.join app_root, 'lib'
14
+ end
13
15
 
14
- def tests_root
15
- File.join app_root, 'test'
16
- end
16
+ def tests_root
17
+ File.join app_root, 'test'
18
+ end
17
19
 
18
- def fixtures_path
19
- File.join(tests_root, 'fixtures')
20
- end
21
20
 
22
- def fixture_path(fixture)
23
- File.join(fixtures_path, fixture)
24
- end
21
+ def fixtures_path
22
+ File.join tests_root, 'fixtures'
23
+ end
24
+
25
+ def fixture_path(*fixture)
26
+ File.join fixtures_path, *fixture
27
+ end
28
+
29
+ def load_fixture(*fixture)
30
+ require fixture_path(*fixture)
31
+ end
25
32
 
26
- def load_fixture(fixture)
27
- require fixture_path(fixture)
33
+ extend self
28
34
  end
29
35
  end
36
+
37
+ class Minitest::Spec
38
+ include Alki::Test
39
+ end
40
+
41
+ unless $LOAD_PATH.include? Alki::Test.lib_dir
42
+ $LOAD_PATH.unshift Alki::Test.lib_dir
43
+ end
44
+
45
+ test_helper_dir = File.join(Alki::Test.tests_root,'test_helper.rb')
46
+
47
+ if File.exists? test_helper_dir
48
+ require test_helper_dir
49
+ end
data/lib/alki/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Alki
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.0"
3
3
  end