alki-dsl 0.3.4 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 950660806cfbd74f9c85f33cb0aa9279d5337e07
4
- data.tar.gz: 7cf697039eaad23ce522769d0e08c735e6d52d41
3
+ metadata.gz: 74a68f3b18db59488fcbe8c2037b3933f33aef5d
4
+ data.tar.gz: '070150789ebbd1bc8b2615395c3e803c0b259913'
5
5
  SHA512:
6
- metadata.gz: 3c5ab25ef97f889ca268c34718ba26eade49cdb7d2f0f00b848d2212f82d1bc25b4873a78cc5028e21e717cbc1ce9c40f45d593da618c17a95fc9e84b7461433
7
- data.tar.gz: 54e8939ddd2a280267d5ca38b21d587296eeb22d43fee1da5683dc48aa73aadea98ea5235ddc3536e4d62d94389a5e8007059520b0bf3dc558bbdd52b4c5b710
6
+ metadata.gz: 420aa794f86a9c2339e784cabd08260d304f500e4c6d6b9731e4b66c7d607153f89a6e1fb3f570a54040a475b7c16e0dbed658f237fd5bab1ee163cbc1e84742
7
+ data.tar.gz: 2a8a0cc25a0fe87a36fe278f5c3ee4768d4816650ead0354dda92e4861ff15e418e5b263ac04e78ef009db02303da87cacc6d996cf667e252dda54d5c2ec2eea
data/README.adoc ADDED
@@ -0,0 +1,277 @@
1
+ # Alki::Dsl
2
+
3
+ Alki::Dsl is a library for building DSLs. The resulting DSL buliders can be used standalone or as builders for
4
+ https://github.com/alki-project/alki-loader[Alki::Loader].
5
+
6
+ Alki::Dsl also allows composing and extending DSLs and comes with built in DSLs for building classes and
7
+ new DSLs.
8
+
9
+ ## Synopsis
10
+
11
+ ```ruby
12
+ require 'alki/dsl'
13
+
14
+ strings_dsl = Alki::Dsl.build 'alki/dsls/dsl' do
15
+ init do
16
+ @strings = []
17
+ end
18
+
19
+ dsl_method :add do |val|
20
+ @strings << val
21
+ end
22
+
23
+ finish do
24
+ ctx[:result] = @strings.join("\n")
25
+ end
26
+ end
27
+
28
+ val = strings_dsl.build do
29
+ add "hello"
30
+ add "world"
31
+ end
32
+
33
+ puts val
34
+
35
+ # output:
36
+ # hello
37
+ # world
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ Add this line to your application's Gemfile:
43
+
44
+ ```ruby
45
+ gem 'alki-dsl'
46
+ ```
47
+
48
+ And then execute:
49
+
50
+ $ bundle
51
+
52
+ Or install it yourself as:
53
+
54
+ $ gem install alki-dsl
55
+
56
+ ## Usage
57
+
58
+ All DSLs created with Alki::Dsl are Class objects with `::build` methods. These build methods take an optional
59
+ hash of parameters, along with a ruby block to be evaluated. DSLs created with Alki::Dsl cannot directly
60
+ strings.
61
+
62
+ While DSLs can be created with Alki::Dsl manually, the easiest way is to use the provided "dsl" DSL. Each
63
+ DSL defines any number of "dsl methods", which are methods that will be exposed to the user of the DSL.
64
+ The DSL can also define "init" and "finish" blocks which will be run before and after the DSL is evaluated.
65
+
66
+ DSLs can "require" other DSLs, causing both of their methods to be available to the user.
67
+
68
+ DSLs are always evaluated within a new instance, so instance variables can be used to store state, however
69
+ these will not be accessible to other DSLs being evaluated at the same time (via requires).
70
+
71
+ Data is passed into and out of a DSL via the `ctx` hash. It is initially set using the hash provided to the
72
+ DSLs build method, but can be updated by code in the DSL. Unlike instance variables, all DSLs being run share
73
+ a single ctx hash, so it can be used to pass data between them.
74
+
75
+ The result of the build method will either be the full ctx hash, or just the value of `ctx[:result]` if it
76
+ exists (including if it's set to false or nil).
77
+
78
+ ```ruby
79
+ require 'alki/dsl'
80
+
81
+ strings_dsl = Alki::Dsl.build 'alki/dsls/dsl' do
82
+ init do # Init block, runs before any dsl methods are called
83
+ ctx[:strings] = [] # Store strings in ctx so other DSLs can access them
84
+ end
85
+
86
+ dsl_method :add do |val| # Simple dsl method called "add"
87
+ ctx[:strings] << val
88
+ end
89
+
90
+ finish do # Finish block, runs after any dsls methods are called
91
+ sep = ctx[:separator] || "\n" # Allow caller of dsl to set the separator
92
+ ctx[:result] = ctx[:strings].join(sep) # Set ctx[:result] so we only return this value
93
+ end
94
+ end
95
+
96
+ my_dsl = Alki::Dsl.build 'alki/dsls/dsl' do
97
+ require_dsl strings_dsl # Require other DSL. Value can also be a "load" string (see Alki::Loader section)
98
+
99
+ init do # This init block will be run *after* the strings_dsl one
100
+ @transform = nil
101
+ end
102
+
103
+ dsl_method :transform do |&blk|
104
+ @transform = blk # Don't need to share this, so just use instance variable
105
+ end
106
+
107
+ finish do # This finish block will be run *before* the strings_dsl one.
108
+ if @transform
109
+ ctx[:strings].map! &@transform
110
+ end
111
+ end
112
+ end
113
+
114
+ result = my_dsl.build(separator: ', ') do # Pass in a separator via data hash
115
+ transform(&:capitalize)
116
+
117
+ add "hello"
118
+ add "world"
119
+ end
120
+
121
+ puts result
122
+
123
+ # output: Hello, World
124
+
125
+ ```
126
+
127
+ ### Using with Alki::Loader
128
+
129
+ https://github.com/alki-project/alki-loader[Alki::Loader] is library that provides extra functionality
130
+ over base Ruby around loading source files. One of its features is to associate "builder" objects with files
131
+ or directories so that the code within them is processed by the builder object when they are loaded. More
132
+ documentation can be found at the Alki::Loader https://github.com/alki-project/alki-loader[github page].
133
+
134
+ The DSLs created by Alki::Dsl can be used as Alki::Loader builder objects, allowing DSLs to be used to define
135
+ classes and modules. In addition, because the provided "dsl" DSL creates classes, it can also be used with
136
+ Alki::Loader to allow defining your DSLs in standalone source files.
137
+
138
+ To get started, in your project create a dsls directory at something like `lib/my_project/dsls`. This will
139
+ be where we put our DSL source files.
140
+
141
+ To register it create a `lib/alki_loader.rb` file:
142
+
143
+ .lib/alki_loader.rb
144
+ ```ruby
145
+ Alki::Loader.register 'my_project/dsls', builder: 'alki/dsls/dsl'
146
+ ```
147
+
148
+ ****
149
+ *Note*: This registers the builder using a string. This is a "load" string and is used frequently in Alki
150
+ projects. When used, the string will be `require`-d and then transformed into a constant name
151
+ (so "alki/dsls/dsl" becomes Alki::Dsls::Dsl) and the resulting class will be used. In addition to less
152
+ typing, this also allows lazy loading behavior, where the file and class are only loaded if needed.
153
+
154
+ The DSL class can be passed directly instead of the load string.
155
+ ****
156
+
157
+ Now a DSL definition file can be created in `lib/my_project/dsls`. Revisiting the previous example, a "strings"
158
+ can be created.
159
+
160
+ .lib/my_project/dsls/strings.rb
161
+ ```ruby
162
+ Alki do
163
+ init do
164
+ ctx[:strings] = []
165
+ end
166
+
167
+ dsl_method :add do |val|
168
+ ctx[:strings] << val
169
+ end
170
+
171
+ finish do
172
+ sep = ctx[:separator] || "\n"
173
+ ctx[:result] = ctx[:strings].join(sep)
174
+ end
175
+ end
176
+ ```
177
+
178
+ The `Alki do ... end` block is part of Alki::Loader and is required. The rest of the DSL is the same
179
+ as before. When this file is loaded by Ruby, it will create a DSL class called MyProject::Dsls::Strings.
180
+
181
+ To use we can require the file normally (making sure to add `lib` to the load path and requiring 'alki/dsl'
182
+ first).
183
+
184
+ ```
185
+ $ irb -Ilib
186
+ > require 'alki/dsl'
187
+ > require 'my_project/dsls/strings'
188
+ > MyProject::Dsls::Strings.build do
189
+ > add "hello"
190
+ > add "world"
191
+ > end
192
+ => "hello\nworld"
193
+ >
194
+ ```
195
+
196
+ The second DSL can now be setup the same way. Note that the `require_dsl` value has been replaced with a load
197
+ string.
198
+
199
+ .lib/my_project/dsls/transformable_strings.rb
200
+ ```ruby
201
+ Alki do
202
+ require_dsl 'my_project/dsls/strings'
203
+
204
+ init do
205
+ @transform = nil
206
+ end
207
+
208
+ dsl_method :transform do |&blk|
209
+ @transform = blk
210
+ end
211
+
212
+ finish do
213
+ if @transform
214
+ ctx[:strings].map! &@transform
215
+ end
216
+ end
217
+ end
218
+ ```
219
+
220
+ So what if we want to use our DSL with Alki::Loader as well? First, Alki::Loader requires builders to
221
+ define a constant with the correct name, so we need code to do that. Alki::Dsl comes with a "class" DSL
222
+ that makes this easy. First lets create a new DSL that adapts our transformable_strings DSL into a module
223
+ builder.
224
+
225
+ .lib/my_project/dsls/strings_class.rb
226
+ ```ruby
227
+ Alki do
228
+ require_dsl 'alki/dsls/class'
229
+ require_dsl 'my_project/dsls/transformable_strings', :after # This makes it's finish runs before ours
230
+
231
+ finish do
232
+ # Helpers provided by alki/dsls/class
233
+ create_as_module # Don't need a class, just a module
234
+ value = ctx[:result]
235
+ add_class_method(:value) { value }
236
+ end
237
+ end
238
+ ```
239
+
240
+ Now we can create a new directory, register it with Alki::Loader, and add a file that uses the DSL. Note
241
+ that we can set separator in the Alki::Loader register call. Any data values set here are passed in
242
+ as `ctx` in the DSL.
243
+
244
+ .lib/alki_loader.rb
245
+ ```ruby
246
+ Alki::Loader.register 'my_project/dsls', builder: 'alki/dsls/dsl'
247
+ Alki::Loader.register 'my_project/strings', builder: 'my_project/dsls/strings_class', separator: ', '
248
+ ```
249
+
250
+ .lib/my_project/strings/hello_world.rb
251
+ ```ruby
252
+ Alki do
253
+ transform &:capitalize
254
+
255
+ add "hello"
256
+ add "world"
257
+ end
258
+ ```
259
+
260
+ ```
261
+ $ irb -Ilib
262
+ > require 'alki/dsl'
263
+ > require 'my_project/strings/hello_world'
264
+ > MyProject::Strings::HelloWorld.value
265
+ => "Hello, World"
266
+ >
267
+ ```
268
+
269
+ ## Contributing
270
+
271
+ Bug reports and pull requests are welcome on GitHub at https://github.com/alki-project/alki-dsl. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the http://contributor-covenant.org[Contributor Covenant] code of conduct.
272
+
273
+
274
+ ## License
275
+
276
+ The gem is available as open source under the terms of the http://opensource.org/licenses/MIT[MIT License].
277
+
data/alki-dsl.gemspec CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency 'alki-support', '~> 0.6'
20
+ spec.add_dependency 'alki-support', '~> 0.7'
21
+ spec.add_dependency 'alki-loader', '~> 0.1'
21
22
  spec.add_development_dependency 'minitest', '~> 5.9', '>= 5.9.1'
22
23
  end
@@ -17,11 +17,9 @@ module Alki
17
17
  end
18
18
 
19
19
  def self.build(data)
20
- class_name = data[:class_name]
21
- if !class_name && data[:name] && data[:prefix]
22
- class_name = Alki::Support.classify(
23
- data[:prefix].empty? ? data[:name] : "#{data[:prefix]}/#{data[:name]}"
24
- )
20
+ class_name = data[:constant_name]
21
+ if !class_name && data[:name]
22
+ class_name = Alki::Support.classify(data[:name])
25
23
  end
26
24
 
27
25
  klass = Alki::Support.constantize class_name, data[:parent_class] if class_name
@@ -40,7 +38,7 @@ module Alki
40
38
  raise "#{class_name} already exists as is a #{klass.class}"
41
39
  end
42
40
  super_class = if data[:super_class]
43
- Alki::Support.load_class data[:super_class]
41
+ Alki.load data[:super_class]
44
42
  else
45
43
  Object
46
44
  end
@@ -59,8 +57,8 @@ module Alki
59
57
  if data[:secondary_classes]
60
58
  data[:secondary_classes].each do |data|
61
59
  if data[:subclass]
62
- data = data.merge(parent_class: klass,class_name: data[:subclass])
63
- elsif !data[:class_name] && !data[:name]
60
+ data = data.merge(parent_class: klass,constant_name: data[:subclass])
61
+ elsif !data[:constant_name] && !data[:name]
64
62
  raise ArgumentError.new("Secondary classes must have names")
65
63
  end
66
64
  build data
data/lib/alki/dsl.rb CHANGED
@@ -1,48 +1,10 @@
1
- require 'alki/dsl/evaluator'
2
- require 'alki/dsl/registry'
1
+ require 'alki/loader'
3
2
 
4
3
  module Alki
5
4
  module Dsl
6
- @loaded = {}
7
- def self.[]=(path,value)
8
- @loaded[path] =value
9
- end
10
-
11
- def self.[](path)
12
- @loaded[path]
13
- end
14
-
15
- def self.register(*args)
16
- Alki::Dsl::Registry.register *args
17
- end
18
-
19
- def self.register_dir(*args)
20
- Alki::Dsl::Registry.register_dir *args
21
- end
22
-
23
- def self.load(path)
24
- path = File.absolute_path(path)
25
- require path
26
- self[path]
27
- end
28
-
29
5
  def self.build(name,data={},&blk)
30
- Alki::Support.load_class(name).build data, &blk
6
+ Alki.load(name).build data, &blk
31
7
  end
32
8
  end
33
9
  end
34
10
 
35
- module Kernel
36
- def Alki(builder=nil,&blk)
37
- if blk
38
- path = caller_locations(1,1)[0].absolute_path
39
- result = if builder
40
- builder.build({}, &blk)
41
- else
42
- Alki::Dsl::Registry.build path, &blk
43
- end
44
- Alki::Dsl[path] = result
45
- end
46
- ::Alki
47
- end
48
- end
@@ -20,29 +20,37 @@ module Alki
20
20
  @finishers.reverse_each(&:call)
21
21
  clear_dsl_methods mod
22
22
 
23
- @processors.each do |processor|
24
- processor.build data
23
+ if data.key? :result
24
+ data[:result]
25
+ else
26
+ data
25
27
  end
26
-
27
- data
28
28
  end
29
29
 
30
30
  def process_dsl(dsl,data)
31
31
  return unless @dsls_seen.add? dsl
32
32
  cbs = dsl.generate(data)
33
+ after_requires = []
33
34
  if cbs[:requires]
34
- cbs[:requires].each do |required_dsl|
35
- process_dsl Alki::Support.load_class(required_dsl), data
35
+ cbs[:requires].each do |(required_dsl,order)|
36
+ case order
37
+ when :before
38
+ process_dsl Alki.load(required_dsl), data
39
+ when :after
40
+ after_requires << [Alki.load(required_dsl), data]
41
+ end
36
42
  end
37
43
  end
38
44
  @inits << cbs[:init] if cbs[:init]
39
45
  @finishers << cbs[:finish] if cbs[:finish]
40
- @processors << cbs[:processors] if cbs[:processors]
41
46
  if cbs[:methods]
42
47
  cbs[:methods].each do |name, proc|
43
48
  define_dsl_method data[:module], name, &proc
44
49
  end
45
50
  end
51
+ after_requires.each do |process_args|
52
+ process_dsl *process_args
53
+ end
46
54
  end
47
55
 
48
56
  def define_dsl_method(mod,name,&blk)
@@ -64,4 +72,4 @@ module Alki
64
72
  end
65
73
  end
66
74
  end
67
- end
75
+ end
@@ -1,5 +1,5 @@
1
1
  module Alki
2
2
  module Dsl
3
- VERSION = '0.3.4'
3
+ VERSION = '0.4.0'
4
4
  end
5
5
  end
@@ -24,7 +24,7 @@ module Alki
24
24
  end
25
25
 
26
26
  def finish
27
- ctx[:class] = Alki::ClassBuilder.build class_builder
27
+ ctx[:result] = Alki::ClassBuilder.build class_builder
28
28
  ctx.delete :class_builder
29
29
  end
30
30
  end
data/lib/alki/dsls/dsl.rb CHANGED
@@ -10,7 +10,7 @@ module Alki
10
10
 
11
11
  def self.dsl_info
12
12
  {
13
- requires: ['alki/dsls/class'],
13
+ requires: [['alki/dsls/class',:before]],
14
14
  methods: [
15
15
  :dsl_method,
16
16
  [:init,:dsl_init],
@@ -49,9 +49,9 @@ module Alki
49
49
  @info[:finish] = :_dsl_finish
50
50
  end
51
51
 
52
- def require_dsl(dsl)
53
- dsl_class = Alki::Support.load_class(dsl)
54
- @info[:requires] << dsl_class
52
+ def require_dsl(dsl, order=:before)
53
+ dsl_class = Alki.load(dsl)
54
+ @info[:requires] << [dsl_class,order]
55
55
  if defined? dsl_class::Helpers
56
56
  add_module dsl_class::Helpers
57
57
  add_helper_module dsl_class::Helpers
@@ -13,7 +13,7 @@ describe 'dsl configuration' do
13
13
  end
14
14
 
15
15
  it 'should allow using dsls specified in same dsl config' do
16
- Kernel.load(fixture_path('example','numbers','three.rb'))
16
+ require 'alki_test/numbers/three'
17
17
  AlkiTest::Numbers::Three.new.must_equal 3
18
18
  end
19
- end
19
+ end
@@ -0,0 +1,2 @@
1
+ Alki::Loader.register '../numbers', builder: 'alki_test/dsls/number', name: 'alki_test/numbers'
2
+ Alki::Loader.register 'alki_test/dsls', builder: 'alki/dsls/dsl'
@@ -105,11 +105,11 @@ describe Alki::ClassBuilder do
105
105
  obj.instance_variable_get(:@b).must_equal 2
106
106
  end
107
107
 
108
- it 'should allow providing a class name' do
108
+ it 'should allow providing a constant name' do
109
109
  if defined?(AlkiTestClass)
110
110
  Object.send :remove_const, :AlkiTestClass
111
111
  end
112
- build(class_name: "AlkiTestClass")
112
+ build(constant_name: "AlkiTestClass")
113
113
  assert(defined?(AlkiTestClass),'Expected AlkiTestClass to be defined')
114
114
  Object.send :remove_const, :AlkiTestClass
115
115
  assert(!defined?(AlkiTestClass))
@@ -119,16 +119,7 @@ describe Alki::ClassBuilder do
119
119
  if defined?(AlkiTest::TestClass)
120
120
  Object.send :remove_const, :AlkiTest
121
121
  end
122
- build(prefix: '', name: "alki_test/test_class")
123
- assert(defined?(AlkiTest::TestClass),'Expected AlkiTest::TestClass to be defined')
124
- Object.send :remove_const, :AlkiTest
125
- end
126
-
127
- it 'should use prefix and name to create class name' do
128
- if defined?(AlkiTest::TestClass)
129
- Object.send :remove_const, :AlkiTest
130
- end
131
- build(prefix: 'alki_test', name: "test_class")
122
+ build(name: "alki_test/test_class")
132
123
  assert(defined?(AlkiTest::TestClass),'Expected AlkiTest::TestClass to be defined')
133
124
  Object.send :remove_const, :AlkiTest
134
125
  end
@@ -137,12 +128,25 @@ describe Alki::ClassBuilder do
137
128
  build(
138
129
  secondary_classes: [
139
130
  {
140
- class_name: 'AlkiTestClass'
131
+ constant_name: 'AlkiTestClass'
141
132
  }
142
133
  ]
143
134
  )
144
135
  assert(defined?(AlkiTestClass),'Expected AlkiTestClass to be defined')
145
136
  Object.send :remove_const, :AlkiTestClass
146
137
  end
138
+
139
+ it 'should allow creating subclasses' do
140
+ build(
141
+ constant_name: 'AlkiTestClass',
142
+ secondary_classes: [
143
+ {
144
+ subclass: 'Subclass'
145
+ }
146
+ ]
147
+ )
148
+ assert(defined?(AlkiTestClass::Subclass),'Expected AlkiTestClass::Subclass to be defined')
149
+ Object.send :remove_const, :AlkiTestClass
150
+ end
147
151
  end
148
152
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alki-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matt Edlefsen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-12-20 00:00:00.000000000 Z
11
+ date: 2016-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: alki-support
@@ -16,14 +16,28 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.6'
19
+ version: '0.7'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.6'
26
+ version: '0.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: alki-loader
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.1'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: minitest
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -53,21 +67,18 @@ extra_rdoc_files: []
53
67
  files:
54
68
  - ".gitignore"
55
69
  - Gemfile
70
+ - README.adoc
56
71
  - alki-dsl.gemspec
57
72
  - lib/alki/class_builder.rb
58
73
  - lib/alki/dsl.rb
59
74
  - lib/alki/dsl/base.rb
60
- - lib/alki/dsl/builder.rb
61
75
  - lib/alki/dsl/class_helpers.rb
62
76
  - lib/alki/dsl/evaluator.rb
63
- - lib/alki/dsl/loader.rb
64
- - lib/alki/dsl/registry.rb
65
77
  - lib/alki/dsl/version.rb
66
78
  - lib/alki/dsls/class.rb
67
79
  - lib/alki/dsls/dsl.rb
68
- - lib/alki/dsls/dsl_config.rb
69
80
  - test/feature/config_test.rb
70
- - test/fixtures/example/config/dsls.rb
81
+ - test/fixtures/example/lib/alki_loader.rb
71
82
  - test/fixtures/example/lib/alki_test/dsls/number.rb
72
83
  - test/fixtures/example/lib/alki_test/dsls/value.rb
73
84
  - test/fixtures/example/numbers/three.rb
@@ -100,7 +111,7 @@ specification_version: 4
100
111
  summary: Alki dsl library
101
112
  test_files:
102
113
  - test/feature/config_test.rb
103
- - test/fixtures/example/config/dsls.rb
114
+ - test/fixtures/example/lib/alki_loader.rb
104
115
  - test/fixtures/example/lib/alki_test/dsls/number.rb
105
116
  - test/fixtures/example/lib/alki_test/dsls/value.rb
106
117
  - test/fixtures/example/numbers/three.rb
@@ -1,42 +0,0 @@
1
- require 'alki/support'
2
- require 'alki/dsl/evaluator'
3
-
4
- module Alki
5
- module Dsl
6
- class Builder
7
- def self.build(data,&blk)
8
- result = Alki::Dsl::Evaluator.evaluate _dsls,data,&blk
9
- if _processor
10
- _processor.build result
11
- else
12
- result
13
- end
14
- end
15
-
16
- private
17
-
18
- def self.dsl(name)
19
- klass = Alki::Support.load_class name
20
- unless klass
21
- raise "Unable to load class #{name.inspect}"
22
- end
23
- dsls = _dsls
24
- dsls += [klass]
25
- define_singleton_method(:_dsls) { dsls }
26
- end
27
-
28
- def self.processor(name)
29
- klass = Alki::Support.load_class name
30
- define_singleton_method(:_processor) { klass }
31
- end
32
-
33
- def self._dsls
34
- []
35
- end
36
-
37
- def self._processor
38
- nil
39
- end
40
- end
41
- end
42
- end
@@ -1,28 +0,0 @@
1
- require 'alki/support'
2
- require 'alki/dsl'
3
-
4
- module Alki
5
- module Dsl
6
- class Loader
7
- def initialize(root_dir)
8
- @root_dir = root_dir
9
- end
10
-
11
- def all_paths
12
- Dir[File.join(@root_dir,'**','*.rb')].map do |path|
13
- path.gsub(File.join(@root_dir,''),'').gsub(/\.rb$/,'')
14
- end
15
- end
16
-
17
- def load_all
18
- all_paths.inject({}) do |h,path|
19
- h.merge!(path => Alki::Dsl.load(path))
20
- end
21
- end
22
-
23
- def load(file)
24
- Alki::Dsl.load File.expand_path("#{file}.rb",@root_dir)
25
- end
26
- end
27
- end
28
- end
@@ -1,76 +0,0 @@
1
- require 'alki/dsl/loader'
2
- require 'alki/support'
3
-
4
- module Alki
5
- module Dsl
6
- module Registry
7
- @registered_paths = {}
8
- @registered_dirs = {}
9
-
10
- def self.registered_paths
11
- @registered_paths.keys
12
- end
13
-
14
- def self.registered_dirs
15
- @registered_dirs.keys
16
- end
17
-
18
- def self.register(path,builder,**data)
19
- @registered_paths[File.absolute_path(path)] = Entry.new(builder,data)
20
- end
21
-
22
- def self.register_dir(dir_path,builder,**data)
23
- @registered_dirs[File.join(File.absolute_path(dir_path),'')] = [builder,data]
24
- end
25
-
26
- def self.lookup(path, load_configs: true)
27
- path = File.absolute_path path
28
- entry = @registered_paths[path]
29
- return entry if entry
30
-
31
- @registered_dirs.each do |dir,(builder,data)|
32
- if path.start_with? dir
33
- data = {name: Alki::Support.path_name(path, dir)}.merge data
34
- return Entry.new(builder,data)
35
- end
36
- end
37
-
38
- if load_configs
39
- root = Alki::Support.find_root(path) do |dir|
40
- File.exists?(File.join(dir,'config','dsls.rb'))
41
- end
42
- if root
43
- config_file = File.join(root,'config','dsls.rb')
44
- register config_file, 'alki/dsls/dsl_config', root: root
45
- require config_file
46
- return lookup path, load_configs: false
47
- end
48
- end
49
-
50
- nil
51
- end
52
-
53
- def self.build(path,&blk)
54
- entry = lookup path
55
- if entry
56
- entry.build blk
57
- else
58
- nil
59
- end
60
- end
61
-
62
- class Entry
63
- attr_reader :data
64
-
65
- def initialize(builder,data)
66
- @builder = builder
67
- @data = data
68
- end
69
-
70
- def build(blk)
71
- Alki::Support.load_class(@builder).build @data, &blk
72
- end
73
- end
74
- end
75
- end
76
- end
@@ -1,28 +0,0 @@
1
- require 'alki/dsl/base'
2
-
3
- module Alki
4
- module Dsls
5
- class DslConfig < Alki::Dsl::Base
6
- def self.dsl_info
7
- {
8
- methods: %i(register register_dir register_lib_dir)
9
- }
10
- end
11
-
12
- def register(path,*args)
13
- path = File.expand_path(path,@ctx[:root])
14
- Alki::Dsl::Registry.register path, *args
15
- end
16
-
17
- def register_dir(path,*args)
18
- path = File.expand_path(path,@ctx[:root])
19
- Alki::Dsl::Registry.register_dir path, *args
20
- end
21
-
22
- def register_lib_dir(prefix,dsl,**data)
23
- path = File.join(@ctx[:root],'lib', prefix)
24
- Alki::Dsl::Registry.register_dir path, dsl, data.merge(prefix: prefix)
25
- end
26
- end
27
- end
28
- end
@@ -1,4 +0,0 @@
1
- Alki do
2
- register_dir 'numbers', 'alki_test/dsls/number', prefix: 'alki_test/numbers'
3
- register_lib_dir 'alki_test/dsls', 'alki/dsls/dsl'
4
- end