alki 0.3.0 → 0.4.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 (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