dsl_compose 1.11.0 → 1.13.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/CHANGELOG.md +14 -0
- data/README.md +18 -7
- data/lib/dsl_compose/interpreter.rb +4 -3
- data/lib/dsl_compose/parser/for_children_of_parser/descendents.rb +41 -0
- data/lib/dsl_compose/parser/for_children_of_parser/for_dsl_parser.rb +3 -3
- data/lib/dsl_compose/parser/for_children_of_parser.rb +54 -10
- data/lib/dsl_compose/parser.rb +19 -5
- data/lib/dsl_compose/version.rb +1 -1
- data/lib/dsl_compose.rb +1 -2
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 45e24e8af1b43cc20cdfe1b9089c54812b774f9d377f4d74842b202d4b6bd1c2
|
4
|
+
data.tar.gz: 55ee3564fadfa1ff647a340a612ef1b840e616054008616565db52838ba2b2eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 307a73bcdd19bda7531e329710d1c559f31f6635d2a7cd495e9cf9644e02db140e53e286ecb9aded78a64b2d11ae617f1178093cb857226346b55bce50fa5ae7
|
7
|
+
data.tar.gz: 837abd419951f900d30a234d0665ff12d2e6cb9ad43750fc2dc58b2d07a5b08a3c9de2faf9c4a0149da65ff4f3aa6381af5b5a67bb1d7c969c6d64429d5cbac8
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [1.13.0](https://github.com/craigulliott/dsl_compose/compare/v1.12.0...v1.13.0) (2023-07-17)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* added for_final_children_of, for_inherited_dsl and for_dsl_or_inherited_dsl methods to the parser ([#35](https://github.com/craigulliott/dsl_compose/issues/35)) ([b01a629](https://github.com/craigulliott/dsl_compose/commit/b01a629e1b18540cbbd90ba53090b41b8fb41dfd))
|
9
|
+
|
10
|
+
## [1.12.0](https://github.com/craigulliott/dsl_compose/compare/v1.11.0...v1.12.0) (2023-07-13)
|
11
|
+
|
12
|
+
|
13
|
+
### Features
|
14
|
+
|
15
|
+
* parsers are now aware of class inheritance, and all classes now assume the DSL configurations of all their ancestors ([#33](https://github.com/craigulliott/dsl_compose/issues/33)) ([6a6cfb1](https://github.com/craigulliott/dsl_compose/commit/6a6cfb1fd9bb44c2ea949888c7b7be14ddc0cef8))
|
16
|
+
|
3
17
|
## [1.11.0](https://github.com/craigulliott/dsl_compose/compare/v1.10.0...v1.11.0) (2023-07-12)
|
4
18
|
|
5
19
|
|
data/README.md
CHANGED
@@ -241,19 +241,30 @@ A parser class can be used to process complicated DSLs. In the example below, a
|
|
241
241
|
# create your own parser by creating a new class which extends DSLCompose::Parser
|
242
242
|
MyParser < DSLCompose::Parser
|
243
243
|
# `for_children_of` will process SomeBaseClass and yield the provided
|
244
|
-
# block once for every class which extends SomeBaseClass
|
245
|
-
#
|
244
|
+
# block once for every class which extends SomeBaseClass.
|
245
|
+
#
|
246
|
+
# If you only want to process classes at the end of the class hierarchy (classes
|
247
|
+
# which extend the provided base class, but do not have their own children) then
|
248
|
+
# use `for_final_children_of` instead of `for_children_of`
|
246
249
|
for_children_of SomeBaseClass do |child_class:|
|
247
|
-
# `for_dsl` accepts a DSL name or an array of DSL names and will yield
|
248
|
-
#
|
249
|
-
#
|
250
|
+
# `for_dsl` accepts a DSL name or an array of DSL names and will yield it's
|
251
|
+
# provided block once for each time a DSL of that name has been used
|
252
|
+
# directly on the child_class.
|
250
253
|
#
|
251
|
-
#
|
254
|
+
# If you want to yield the provided block for classes which didn't directly use
|
255
|
+
# one of the provided DSLs, but the DSL was used on one of their ancestors, then
|
256
|
+
# use `for_inherited_dsl :dsl_name` instead of `for_dsl :dsl_name`. If you want
|
257
|
+
# the block to yield whether the DSL was used directly on the provided class or
|
258
|
+
# anywhere in it's ancestor chain, then use `for_dsl_or_inherited_dsl :dsl_name`.
|
259
|
+
#
|
260
|
+
# An error will be raised if any of the provided DSL names does not exist.
|
252
261
|
#
|
253
262
|
# You can optionally provide keyword arguments which correspond to any
|
254
263
|
# arguments that were defined for the DSL, if multiple dsl names are provided
|
255
264
|
# then the requested dsl argument must be present on all DSLs otherwise an
|
256
|
-
# error will be raised.
|
265
|
+
# error will be raised. The parser is aware of class inheritance, and will
|
266
|
+
# consider a DSL to have been executed on the actual class it was used, and
|
267
|
+
# any classes which are descendants of that class
|
257
268
|
for_dsl [:dsl1, :dsl2] do |dsl_name:, a_dsl_argument:|
|
258
269
|
# `for_method` accepts a method name or an array of method names and will
|
259
270
|
# yield it's provided block once for each time a method with this name is
|
@@ -40,9 +40,10 @@ module DSLCompose
|
|
40
40
|
@executions.filter { |e| e.dsl.name == dsl_name }
|
41
41
|
end
|
42
42
|
|
43
|
-
# Returns an array of all executions for a given name and class.
|
44
|
-
|
45
|
-
|
43
|
+
# Returns an array of all executions for a given name and class. This includes
|
44
|
+
# any ancestors of the provided class
|
45
|
+
def class_dsl_executions klass, dsl_name, on_current_class, on_ancestor_class
|
46
|
+
@executions.filter { |e| e.dsl.name == dsl_name && ((on_current_class && e.klass == klass) || (on_ancestor_class && klass < e.klass)) }
|
46
47
|
end
|
47
48
|
|
48
49
|
# removes all executions from the interpreter, this is primarily used from
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module DSLCompose
|
4
|
+
class Parser
|
5
|
+
class ForChildrenOfParser
|
6
|
+
class Descendents
|
7
|
+
def initialize base_class, final_children_only
|
8
|
+
@base_class = base_class
|
9
|
+
@final_children_only = final_children_only
|
10
|
+
end
|
11
|
+
|
12
|
+
def classes
|
13
|
+
# all objects which extend the provided base class
|
14
|
+
extending_classes = ObjectSpace.each_object(Class).select { |klass| klass < @base_class }
|
15
|
+
|
16
|
+
# sort the results, classes are ordered first by the depth of their namespace, and second
|
17
|
+
# by their name
|
18
|
+
extending_classes.sort_by! do |child_class|
|
19
|
+
"#{child_class.name.split("::").count}_#{child_class.name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
# if this is not a final child, but we are processing final children only, then skip it
|
23
|
+
if @final_children_only
|
24
|
+
# reject any classes which have descendents
|
25
|
+
extending_classes.reject! do |child_class|
|
26
|
+
has_descendents child_class
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
extending_classes
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def has_descendents base_class
|
36
|
+
ObjectSpace.each_object(Class).count { |klass| klass < base_class } > 0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -20,7 +20,7 @@ module DSLCompose
|
|
20
20
|
# of the provided name is used by the child class.
|
21
21
|
#
|
22
22
|
# base_class and child_class are set from the ForChildrenOfParser
|
23
|
-
def initialize base_class, child_class, dsl_names, &block
|
23
|
+
def initialize base_class, child_class, dsl_names, on_current_class, on_ancestor_class, &block
|
24
24
|
@base_class = base_class
|
25
25
|
@child_class = child_class
|
26
26
|
@dsl_names = dsl_names
|
@@ -31,7 +31,7 @@ module DSLCompose
|
|
31
31
|
end
|
32
32
|
|
33
33
|
# if any arguments were provided, then assert that they are valid
|
34
|
-
if block
|
34
|
+
if block&.parameters&.any?
|
35
35
|
# all parameters must be keyword arguments
|
36
36
|
if block.parameters.filter { |p| p.first != :keyreq }.any?
|
37
37
|
raise AllBlockParametersMustBeKeywordParametersError, "All block parameters must be keyword parameters, i.e. `for_dsl :dsl_name do |dsl_name:|`"
|
@@ -62,7 +62,7 @@ module DSLCompose
|
|
62
62
|
dsl_names.each do |dsl_name|
|
63
63
|
# a dsl can be execued multiple times on a class, so we find all of the executions
|
64
64
|
# here and then yield the block once for each execution
|
65
|
-
base_class.dsls.class_dsl_executions(child_class, dsl_name).each do |dsl_execution|
|
65
|
+
base_class.dsls.class_dsl_executions(child_class, dsl_name, on_current_class, on_ancestor_class).each do |dsl_execution|
|
66
66
|
# we only provide the requested arguments to the block, this allows
|
67
67
|
# us to use keyword arguments to force a naming convention on these arguments
|
68
68
|
# and to validate their use
|
@@ -15,9 +15,27 @@ module DSLCompose
|
|
15
15
|
class NoChildClassError < StandardError
|
16
16
|
end
|
17
17
|
|
18
|
-
# This class will yield to the provided block for each
|
19
|
-
#
|
20
|
-
|
18
|
+
# This class will yield to the provided block for each descendant
|
19
|
+
# class of the provided base_class
|
20
|
+
#
|
21
|
+
# For example:
|
22
|
+
#
|
23
|
+
# class BaseClass
|
24
|
+
# include DSLCompose::Composer
|
25
|
+
# define_dsl :my_foo_dsl
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# class ChildClass < BaseClass
|
29
|
+
# my_foo_dsl
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# class GrandchildClass < ChildClass
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# parser.for_children_of BaseClass do |child_class:|
|
36
|
+
# # this will yield for ChildClass and GrandchildClass
|
37
|
+
# and
|
38
|
+
def initialize base_class, final_children_only, &block
|
21
39
|
# assert the provided class has the DSLCompose::Composer module installed
|
22
40
|
unless base_class.respond_to? :dsls
|
23
41
|
raise ClassDoesNotUseDSLComposeError, base_class
|
@@ -31,23 +49,25 @@ module DSLCompose
|
|
31
49
|
end
|
32
50
|
|
33
51
|
# if any arguments were provided, then assert that they are valid
|
34
|
-
if block
|
52
|
+
if block&.parameters&.any?
|
35
53
|
# all parameters must be keyword arguments
|
36
54
|
if block.parameters.filter { |p| p.first != :keyreq }.any?
|
37
55
|
raise AllBlockParametersMustBeKeywordParametersError, "All block parameters must be keyword parameters, i.e. `for_children_of FooClass do |base_class:|`"
|
38
56
|
end
|
39
57
|
end
|
40
58
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
59
|
+
# yeild the block for all descendents of the provided base_class
|
60
|
+
Descendents.new(base_class, final_children_only).classes.each do |child_class|
|
61
|
+
# determine which arguments to send to the block
|
44
62
|
args = {}
|
45
63
|
if BlockArguments.accepts_argument?(:child_class, &block)
|
46
64
|
args[:child_class] = child_class
|
47
65
|
end
|
66
|
+
|
48
67
|
# set the child_class in an instance variable so that method calls to
|
49
68
|
# `for_dsl` from within the block will have access to it
|
50
69
|
@child_class = child_class
|
70
|
+
|
51
71
|
# yield the block in the context of this class
|
52
72
|
instance_exec(**args, &block)
|
53
73
|
end
|
@@ -57,7 +77,7 @@ module DSLCompose
|
|
57
77
|
|
58
78
|
# Given a dsl name, or array of dsl names, this method will yield to the
|
59
79
|
# provided block once for each time a dsl with one of the provided names
|
60
|
-
# was used on the correspondng child_class
|
80
|
+
# was used on the correspondng child_class or any of its ancestors.
|
61
81
|
#
|
62
82
|
# The value of child_class and base_class are set from the yield of this
|
63
83
|
# classes initializer, meaning that the use of this method should look
|
@@ -68,14 +88,38 @@ module DSLCompose
|
|
68
88
|
# ...
|
69
89
|
# end
|
70
90
|
# end
|
71
|
-
|
91
|
+
#
|
92
|
+
# If `on_current_class` is true, then the block will be yielded to for each DSL
|
93
|
+
# which was used directly on the current class. If `oncurrent_class` is false,
|
94
|
+
# then the block will not be yielded to for any DSL which was used directly on.
|
95
|
+
# If `on_ancestor_class` is true, then the block will be yielded to for each DSL
|
96
|
+
# which was used on any class in the current classes ancestry. If `on_ancestor_class`
|
97
|
+
# is false, then the block will not be yielded to for any DSL which was used on
|
98
|
+
# any class in the current classes ancestry.
|
99
|
+
def for_dsl dsl_names, on_current_class: true, on_ancestor_class: false, &block
|
72
100
|
child_class = @child_class
|
73
101
|
|
74
102
|
unless child_class
|
75
103
|
raise NoChildClassError, "No child_class was found, please call this method from within a `for_children_of` block"
|
76
104
|
end
|
77
105
|
|
78
|
-
ForDSLParser.new(@base_class, child_class, dsl_names, &block)
|
106
|
+
ForDSLParser.new(@base_class, child_class, dsl_names, on_current_class, on_ancestor_class, &block)
|
107
|
+
end
|
108
|
+
|
109
|
+
# this is a wrapper for the `for_dsl` method, but it provides a value of true
|
110
|
+
# for the `on_ancestor_class` argument and a value of false for the `on_current_class`
|
111
|
+
# argument. This will cause the parser to only yeild for dsls which were used on
|
112
|
+
# a class which is in the current classes ancestry, but not on the current class
|
113
|
+
def for_inherited_dsl dsl_names, &block
|
114
|
+
for_dsl dsl_names, on_current_class: false, on_ancestor_class: true, &block
|
115
|
+
end
|
116
|
+
|
117
|
+
# this is a wrapper for the `for_dsl` method, but it provides a value of true
|
118
|
+
# for the `on_ancestor_class` argument and a value of true for the `on_current_class`
|
119
|
+
# argument. This will cause the parser to yeild for dsls which were used on either
|
120
|
+
# the current class or any class in its ancestry
|
121
|
+
def for_dsl_or_inherited_dsl dsl_names, &block
|
122
|
+
for_dsl dsl_names, on_current_class: true, on_ancestor_class: true, &block
|
79
123
|
end
|
80
124
|
end
|
81
125
|
end
|
data/lib/dsl_compose/parser.rb
CHANGED
@@ -24,30 +24,44 @@ module DSLCompose
|
|
24
24
|
raise NotInitializable
|
25
25
|
end
|
26
26
|
|
27
|
-
#
|
27
|
+
# The first step in defining a parser is to set the base_class, this method
|
28
28
|
# will yield to the provided block for each child class of the provided base_class
|
29
|
-
# provided that the child_class uses at least one of the base_classes defined DSLs
|
30
|
-
|
29
|
+
# provided that the child_class uses at least one of the base_classes defined DSLs.
|
30
|
+
# If `final_children_only` is true, then this will cause the parser to only return
|
31
|
+
# classes which are at the end of their class hierachy (meaning they dont have any
|
32
|
+
# children of their own)
|
33
|
+
def self.for_children_of base_class, final_children_only: false, rerun: false, &block
|
31
34
|
unless rerun
|
32
35
|
@runs ||= []
|
33
36
|
@runs << {
|
34
37
|
base_class: base_class,
|
38
|
+
final_children_only: final_children_only,
|
35
39
|
block: block
|
36
40
|
}
|
37
41
|
end
|
38
42
|
|
39
43
|
# we parse the provided block in the context of the ForChildrenOfParser class
|
40
44
|
# to help make this code more readable, and to limit polluting the current namespace
|
41
|
-
ForChildrenOfParser.new(base_class, &block)
|
45
|
+
ForChildrenOfParser.new(base_class, final_children_only, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
# this is a wrapper for the `for_children_of` method, but it provides a value
|
49
|
+
# of true for the `final_children_only` argument. This will cause the parser to only
|
50
|
+
# return classes which are at the end of the class hierachy (meaning they dont have
|
51
|
+
# any children of their own)
|
52
|
+
def self.for_final_children_of base_class, &block
|
53
|
+
for_children_of base_class, final_children_only: true, &block
|
42
54
|
end
|
43
55
|
|
44
56
|
# this method is used to rerun the parser, this is most useful from within a test suite
|
45
57
|
# when you are testing the parser itself
|
46
58
|
def self.rerun
|
59
|
+
# rerun each parset tests
|
47
60
|
@runs&.each do |run|
|
48
61
|
base_class = run[:base_class]
|
49
62
|
block = run[:block]
|
50
|
-
|
63
|
+
final_children_only = run[:final_children_only]
|
64
|
+
for_children_of base_class, rerun: true, final_children_only: final_children_only, &block
|
51
65
|
end
|
52
66
|
end
|
53
67
|
end
|
data/lib/dsl_compose/version.rb
CHANGED
data/lib/dsl_compose.rb
CHANGED
@@ -36,6 +36,7 @@ require "dsl_compose/interpreter"
|
|
36
36
|
|
37
37
|
require "dsl_compose/parser/for_children_of_parser/for_dsl_parser/for_method_parser"
|
38
38
|
require "dsl_compose/parser/for_children_of_parser/for_dsl_parser"
|
39
|
+
require "dsl_compose/parser/for_children_of_parser/descendents"
|
39
40
|
require "dsl_compose/parser/for_children_of_parser"
|
40
41
|
require "dsl_compose/parser/block_arguments"
|
41
42
|
require "dsl_compose/parser"
|
@@ -49,6 +50,4 @@ require "dsl_compose/shared_configuration"
|
|
49
50
|
require "dsl_compose/dsls"
|
50
51
|
|
51
52
|
module DSLCompose
|
52
|
-
class Error < StandardError
|
53
|
-
end
|
54
53
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dsl_compose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Craig Ulliott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07-
|
12
|
-
dependencies:
|
11
|
+
date: 2023-07-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: class_spec_helper
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description: Ruby gem to add dynamic DSLs to classes. DSLs are added to classes by
|
14
28
|
including the DSLCompose module, and then calling the add_dsl singleton method within
|
15
29
|
the class or a child class.
|
@@ -56,6 +70,7 @@ files:
|
|
56
70
|
- lib/dsl_compose/parser.rb
|
57
71
|
- lib/dsl_compose/parser/block_arguments.rb
|
58
72
|
- lib/dsl_compose/parser/for_children_of_parser.rb
|
73
|
+
- lib/dsl_compose/parser/for_children_of_parser/descendents.rb
|
59
74
|
- lib/dsl_compose/parser/for_children_of_parser/for_dsl_parser.rb
|
60
75
|
- lib/dsl_compose/parser/for_children_of_parser/for_dsl_parser/for_method_parser.rb
|
61
76
|
- lib/dsl_compose/shared_configuration.rb
|