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 +4 -4
- data/README.adoc +277 -0
- data/alki-dsl.gemspec +2 -1
- data/lib/alki/class_builder.rb +6 -8
- data/lib/alki/dsl.rb +2 -40
- data/lib/alki/dsl/evaluator.rb +16 -8
- data/lib/alki/dsl/version.rb +1 -1
- data/lib/alki/dsls/class.rb +1 -1
- data/lib/alki/dsls/dsl.rb +4 -4
- data/test/feature/config_test.rb +2 -2
- data/test/fixtures/example/lib/alki_loader.rb +2 -0
- data/test/integration/class_builder_test.rb +17 -13
- metadata +21 -10
- data/lib/alki/dsl/builder.rb +0 -42
- data/lib/alki/dsl/loader.rb +0 -28
- data/lib/alki/dsl/registry.rb +0 -76
- data/lib/alki/dsls/dsl_config.rb +0 -28
- data/test/fixtures/example/config/dsls.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 74a68f3b18db59488fcbe8c2037b3933f33aef5d
|
4
|
+
data.tar.gz: '070150789ebbd1bc8b2615395c3e803c0b259913'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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
|
data/lib/alki/class_builder.rb
CHANGED
@@ -17,11 +17,9 @@ module Alki
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def self.build(data)
|
20
|
-
class_name = data[:
|
21
|
-
if !class_name && data[:name]
|
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
|
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,
|
63
|
-
elsif !data[:
|
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/
|
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
|
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
|
data/lib/alki/dsl/evaluator.rb
CHANGED
@@ -20,29 +20,37 @@ module Alki
|
|
20
20
|
@finishers.reverse_each(&:call)
|
21
21
|
clear_dsl_methods mod
|
22
22
|
|
23
|
-
|
24
|
-
|
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
|
-
|
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
|
data/lib/alki/dsl/version.rb
CHANGED
data/lib/alki/dsls/class.rb
CHANGED
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
|
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
|
data/test/feature/config_test.rb
CHANGED
@@ -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
|
-
|
16
|
+
require 'alki_test/numbers/three'
|
17
17
|
AlkiTest::Numbers::Three.new.must_equal 3
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
@@ -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
|
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(
|
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(
|
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
|
-
|
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.
|
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-
|
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.
|
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.
|
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/
|
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/
|
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
|
data/lib/alki/dsl/builder.rb
DELETED
@@ -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
|
data/lib/alki/dsl/loader.rb
DELETED
@@ -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
|
data/lib/alki/dsl/registry.rb
DELETED
@@ -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
|
data/lib/alki/dsls/dsl_config.rb
DELETED
@@ -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
|