dsl_compose 1.9.1 → 1.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7fc1bd78d6f3926b9ee718a6e2191cefd5aecd40fcfbb5de9a8cfbd8c602e65c
4
- data.tar.gz: 7b9fd87ecf61b71831f56ab9120562cb3fbb3d49424dc7862c31014e6dc96d45
3
+ metadata.gz: c6a23cf9faddf37ebe1fdec13fe554e8e7601e01f5c53495d8d3d37f28a63faf
4
+ data.tar.gz: 7254f3f5c46716e462189c72d2bd02b0131cdca1fb39387a8b86fd79cb2e9c6c
5
5
  SHA512:
6
- metadata.gz: d3f750f7d8d5d1d7b2014cd84ad10d656d005e2738b18c8ed89f108656b5f9037a428f6ec1094af5382d9788985f3c205c68f06198c8a18e2dfc01f518203cb6
7
- data.tar.gz: 12a823a699962ee5426a53ab66517f5acb23bd1fbc6834b219d6209d09ba78a9a9b249a1169497a0a2773287f24abf2d7c065c3f126f702bf4927c13180a15aa
6
+ metadata.gz: c71462286d85bdc0b4f2d3879b08bf04a142b4f10bb9554c230fa263d80e69d08fe73bd3cc198d516d8950df1a8b39863823cf0993b3a80af2110b80de69f2a6
7
+ data.tar.gz: 5b03471c8e676610297c16312b517bd62692fa5d85e5a610aed709684058032764668550622c84089d4cc6b7240d76c2d6a9d21487a4abf074eecaf93b6c19bd
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.11.0](https://github.com/craigulliott/dsl_compose/compare/v1.10.0...v1.11.0) (2023-07-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * arguments can optionally accept arrays of values, also added a :class and :object type, and an associated "is_a" validator for :object ([#31](https://github.com/craigulliott/dsl_compose/issues/31)) ([acd7034](https://github.com/craigulliott/dsl_compose/commit/acd70345a4d1873e657d0e897f527269ca320453))
9
+
10
+ ## [1.10.0](https://github.com/craigulliott/dsl_compose/compare/v1.9.1...v1.10.0) (2023-07-11)
11
+
12
+
13
+ ### Features
14
+
15
+ * ability to easily share configuration between multiple DSLs ([#27](https://github.com/craigulliott/dsl_compose/issues/27)) ([38ff61b](https://github.com/craigulliott/dsl_compose/commit/38ff61bed7c9d4357a0019c40fc20bc54d62bebb))
16
+
3
17
  ## [1.9.1](https://github.com/craigulliott/dsl_compose/compare/v1.9.0...v1.9.1) (2023-07-11)
4
18
 
5
19
 
data/README.md CHANGED
@@ -15,6 +15,7 @@ Ruby gem to add dynamic DSLs to classes
15
15
  * Automatically generate documentation for your DSLs
16
16
  * Extensive test coverage
17
17
  * Very lightweight and no external dependencies
18
+ * Share common DSL configuration between DSLs
18
19
 
19
20
  ## Installation
20
21
 
@@ -53,7 +54,9 @@ class Foo
53
54
  # `required`)
54
55
  #
55
56
  # Arguments are validated, and their expected type must be defined. Supported
56
- # argument types are :integer, :boolean, :float, :string or :symbol
57
+ # argument types are :integer, :boolean, :float, :string, :symbol, :class or :object
58
+ # when :class is used, it should be provided to your final DSL as a string of the
59
+ # classes name, such as "Users::UserModel" and not the actual class.
57
60
  requires :first_dsl_argument, :symbol do
58
61
  # You should provide descriptions for your arguments. These descriptions will
59
62
  # be used when generating your documentation. This description supports markdown
@@ -110,6 +113,16 @@ class Foo
110
113
  # You can add validation to your arguments. A full list is provided later in this document
111
114
  validate_greater_than 0
112
115
  end
116
+
117
+ # All optional and required arguments can optionally accept an array of values. When using
118
+ # your final DSL, a single item can be provided but will automatically be converted to an
119
+ # array of items. All items in the array must be of the expected type.
120
+ optional :another_optional_argument, :object, array: true do
121
+ description "A description of an optional argument which accepts an array"
122
+
123
+ # You can add validation to your arguments. A full list is provided later in this document
124
+ validate_is_a Date
125
+ end
113
126
  end
114
127
 
115
128
  end
@@ -117,6 +130,39 @@ end
117
130
 
118
131
  ```
119
132
 
133
+ ### Shared Configuration
134
+
135
+ If you are composing many DSLs across one or many classes and these DSLs share common configuration, then you can share configuration between them.
136
+
137
+ Define your shared configuration
138
+
139
+ ```ruby
140
+ DSLCompose::SharedConfiguration.add :my_common_validators do
141
+ validate_not_end_with [:_id, :_at, :_count, :_type]
142
+ validate_not_in [:type, :stage]
143
+ validate_length minimum: 0, maximum: 10
144
+ validate_format /\A[a-z]+(_[a-z]+)*\Z/
145
+ end
146
+ ```
147
+
148
+ Use your shared DSL from within any of your DSL compositions
149
+
150
+ ```ruby
151
+ class Foo
152
+ include DSLCompose::Composer
153
+
154
+ define_dsl :your_dsl do
155
+ optional :optional_argument, :integer do
156
+ # this will import and apply your shared configuration
157
+ import_shared :my_common_validators
158
+ end
159
+
160
+ end
161
+ end
162
+ ```
163
+
164
+ You can use `import_shared` anywhere within your DSL definition, you can even use `import_shared` within other shared configuration
165
+
120
166
  ### Using your DSL
121
167
 
122
168
  Child classes can then use your new DSL
@@ -380,6 +426,42 @@ The following validations can be added to the arguments of your DSL methods. Val
380
426
  end
381
427
  ```
382
428
 
429
+ ### Class attributes (:class)
430
+
431
+ ```ruby
432
+ define_dsl :my_dsl do
433
+ add_method :my_method do
434
+
435
+ requires :my_first_argument, :class do
436
+
437
+ # There are no validations for :class types
438
+
439
+ end
440
+
441
+ end
442
+ end
443
+ ```
444
+
445
+ ### Object attributes (:object)
446
+
447
+ ```ruby
448
+ define_dsl :my_dsl do
449
+ add_method :my_method do
450
+
451
+ requires :my_first_argument, :object do
452
+
453
+ # The provided attribute must be an instantiated object which
454
+ # is an instance of the class.
455
+ #
456
+ # For example, this would accept a regexp object such as /[a-z]+/
457
+ validate_is_a Regexp
458
+
459
+ end
460
+
461
+ end
462
+ end
463
+ ```
464
+
383
465
 
384
466
  ## Development
385
467
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSLCompose
4
+ class ClassCoerce
5
+ class UnexpectedClassNameError < StandardError
6
+ end
7
+
8
+ def initialize class_name
9
+ unless class_name.is_a? String
10
+ raise UnexpectedClassNameError, "expected `#{class_name}` to be a String"
11
+ end
12
+
13
+ @class_name = class_name
14
+ end
15
+
16
+ def to_class
17
+ Object.const_get @class_name
18
+ end
19
+ end
20
+ end
@@ -99,6 +99,19 @@ module DSLCompose
99
99
  def validate_format regexp
100
100
  @argument.validate_format regexp
101
101
  end
102
+
103
+ # adds an 'is a' validator to the argument
104
+ def validate_is_a klass
105
+ @argument.validate_is_a klass
106
+ end
107
+
108
+ # executes the shared configuration block with the given name within the
109
+ # context of this part of the DSL, this is a mechanism to share configuration
110
+ # between DSLs
111
+ def import_shared shared_configuration_name
112
+ block = SharedConfiguration.get shared_configuration_name
113
+ instance_eval(&block)
114
+ end
102
115
  end
103
116
  end
104
117
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSLCompose
4
+ class DSL
5
+ class Arguments
6
+ class Argument
7
+ class IsAValidation
8
+ class ValidationFailedError < StandardError
9
+ end
10
+
11
+ def initialize value
12
+ @value = value
13
+ end
14
+
15
+ def validate! value
16
+ raise ValidationFailedError, "The argument is invalid. Expected #{value} to be an instance of #{@value}" unless value.is_a?(@value)
17
+ true
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -42,6 +42,9 @@ module DSLCompose
42
42
  attr_reader :type
43
43
  # if required, then this Argument must be provided when calling its associated DSLMethod.
44
44
  attr_reader :required
45
+ # If true, then this argument accepts an array of values. It will also accept a single value,
46
+ # but that single value will be automatically converted to an array
47
+ attr_reader :array
45
48
  # An otional description of this Attribute, if provided then it must be a string.
46
49
  # The description accepts markdown and is used when generating documentation.
47
50
  attr_reader :description
@@ -61,6 +64,7 @@ module DSLCompose
61
64
  attr_reader :start_with_validation
62
65
  attr_reader :not_start_with_validation
63
66
  attr_reader :length_validation
67
+ attr_reader :is_a_validation
64
68
 
65
69
  # Create a new Attribute object.
66
70
  #
@@ -69,7 +73,7 @@ module DSLCompose
69
73
  # calling its associated DSLMethod.
70
74
  # `type` can be either :integer, :boolean, :float, :string or :symbol
71
75
  # `block` contains the instructions to further configure this Attribute
72
- def initialize name, required, type, &block
76
+ def initialize name, required, type, array: false, &block
73
77
  if name.is_a? Symbol
74
78
 
75
79
  if RESERVED_ARGUMENT_NAMES.include? name
@@ -81,14 +85,16 @@ module DSLCompose
81
85
  raise InvalidNameError, "The option name `#{name}` is invalid, it must be of type symbol."
82
86
  end
83
87
 
84
- if type == :integer || type == :boolean || type == :float || type == :string || type == :symbol
88
+ if type == :integer || type == :boolean || type == :float || type == :string || type == :symbol || type == :class || type == :object
85
89
  @type = type
86
90
  else
87
- raise InvalidTypeError, "Argument type `#{type}` must be one of :integer, :boolean, :float, :string or :symbol"
91
+ raise InvalidTypeError, "Argument type `#{type}` must be one of :integer, :boolean, :float, :string, :symbol, :class or :object"
88
92
  end
89
93
 
90
94
  @required = required ? true : false
91
95
 
96
+ @array = array ? true : false
97
+
92
98
  # If a block was provided, then we evaluate it using a seperate
93
99
  # interpreter class. We do this because the interpreter class contains
94
100
  # no other methods or variables, if it was evaluated in the context of
@@ -331,6 +337,18 @@ module DSLCompose
331
337
  @length_validation = LengthValidation.new(maximum: maximum, minimum: minimum, is: is)
332
338
  end
333
339
 
340
+ def validate_is_a klass
341
+ if @is_a_validation
342
+ raise ValidationAlreadyExistsError, "The validation `is_a` has already been applied to this method option."
343
+ end
344
+
345
+ unless @type == :object
346
+ raise ValidationIncompatibleError, "The validation type #{@type} is not compatible with this argument type"
347
+ end
348
+
349
+ @is_a_validation = IsAValidation.new(klass)
350
+ end
351
+
334
352
  # returns true if every provided integer validation also returns true
335
353
  def validate_integer! value
336
354
  (greater_than_validation.nil? || greater_than_validation.validate!(value)) &&
@@ -374,6 +392,17 @@ module DSLCompose
374
392
  def validate_boolean! value
375
393
  (equal_to_validation.nil? || equal_to_validation.validate!(value))
376
394
  end
395
+
396
+ # returns true if every provided class validation also returns true
397
+ def validate_class! value
398
+ # there are no class validations
399
+ true
400
+ end
401
+
402
+ # returns true if every provided object validation also returns true
403
+ def validate_object! value
404
+ (is_a_validation.nil? || is_a_validation.validate!(value))
405
+ end
377
406
  end
378
407
  end
379
408
  end
@@ -81,7 +81,7 @@ module DSLCompose
81
81
  # Argument `name` must be unique within the DSLMethod.
82
82
  # `required` must be a boolean, and determines if this argument will be required
83
83
  # or optional on the method which is exposed in our DSL.
84
- def add_argument name, required, type, &block
84
+ def add_argument name, required, type, array: false, &block
85
85
  if @arguments.key? name
86
86
  raise ArgumentAlreadyExistsError, "An argument with the name `#{name}` already exists for this DSL method"
87
87
  end
@@ -91,7 +91,7 @@ module DSLCompose
91
91
  raise ArgumentOrderingError, "Required arguments can not be added after optional ones"
92
92
  end
93
93
 
94
- @arguments[name] = Argument.new(name, required, type, &block)
94
+ @arguments[name] = Argument.new(name, required, type, array: array, &block)
95
95
  end
96
96
  end
97
97
  end
@@ -38,8 +38,8 @@ module DSLCompose
38
38
  # `type` can be either :integer, :boolean, :float, :string or :symbol
39
39
  # `block` contains the argument definition and will be evaluated seperately
40
40
  # by the Argument::Interpreter
41
- def optional name, type, &block
42
- @dsl_method.arguments.add_argument name, false, type, &block
41
+ def optional name, type, array: false, &block
42
+ @dsl_method.arguments.add_argument name, false, type, array: array, &block
43
43
  end
44
44
 
45
45
  # adds a new required argument to the DSLMethod
@@ -48,8 +48,16 @@ module DSLCompose
48
48
  # `type` can be either :integer, :boolean, :float, :string or :symbol
49
49
  # `block` contains the argument definition and will be evaluated seperately
50
50
  # by the Argument::Interpreter
51
- def requires name, type, &block
52
- @dsl_method.arguments.add_argument name, true, type, &block
51
+ def requires name, type, array: false, &block
52
+ @dsl_method.arguments.add_argument name, true, type, array: array, &block
53
+ end
54
+
55
+ # executes the shared configuration block with the given name within the
56
+ # context of this part of the DSL, this is a mechanism to share configuration
57
+ # between DSLs
58
+ def import_shared shared_configuration_name
59
+ block = SharedConfiguration.get shared_configuration_name
60
+ instance_eval(&block)
53
61
  end
54
62
  end
55
63
  end
@@ -54,8 +54,8 @@ module DSLCompose
54
54
  # `type` can be either :integer, :boolean, :float, :string or :symbol
55
55
  # `block` contains the argument definition and will be evaluated seperately
56
56
  # by the Argument::Interpreter
57
- def optional name, type, &block
58
- @dsl.arguments.add_argument name, false, type, &block
57
+ def optional name, type, array: false, &block
58
+ @dsl.arguments.add_argument name, false, type, array: array, &block
59
59
  end
60
60
 
61
61
  # adds a new required argument to the DSLMethod
@@ -64,8 +64,16 @@ module DSLCompose
64
64
  # `type` can be either :integer, :boolean, :float, :string or :symbol
65
65
  # `block` contains the argument definition and will be evaluated seperately
66
66
  # by the Argument::Interpreter
67
- def requires name, type, &block
68
- @dsl.arguments.add_argument name, true, type, &block
67
+ def requires name, type, array: false, &block
68
+ @dsl.arguments.add_argument name, true, type, array: array, &block
69
+ end
70
+
71
+ # executes the shared configuration block with the given name within the
72
+ # context of this part of the DSL, this is a mechanism to share configuration
73
+ # between DSLs
74
+ def import_shared shared_configuration_name
75
+ block = SharedConfiguration.get shared_configuration_name
76
+ instance_eval(&block)
69
77
  end
70
78
  end
71
79
  end
@@ -16,6 +16,9 @@ module DSLCompose
16
16
  class InvalidArgumentTypeError < StandardError
17
17
  end
18
18
 
19
+ class ArrayNotValidError < StandardError
20
+ end
21
+
19
22
  attr_reader :arguments
20
23
 
21
24
  def initialize arguments, *args
@@ -49,41 +52,80 @@ module DSLCompose
49
52
 
50
53
  # assert the each provided optional argument is valid
51
54
  optional_arg.keys.each do |optional_argument_name|
52
- optional_arg_value = optional_arg[optional_argument_name]
53
55
  optional_argument = arguments.optional_argument optional_argument_name
54
56
 
55
- case optional_argument.type
56
- when :integer
57
- unless optional_arg_value.is_a? Integer
58
- raise InvalidArgumentTypeError, "#{optional_arg_value} is not an Integer"
59
- end
60
- optional_argument.validate_integer! optional_arg_value
61
-
62
- when :symbol
63
- unless optional_arg_value.is_a? Symbol
64
- raise InvalidArgumentTypeError, "#{optional_arg_value} is not a Symbol"
57
+ # the value for class types are wrapped in a ClassCoerce class so that they can be
58
+ # treated specially by the parser (it automatically converts them from a string name
59
+ # to the corresponding class, logic which doesn't happen here in case the class doesnt
60
+ # exist yet)
61
+ optional_arg_value = if optional_argument.type == :class
62
+ if optional_arg[optional_argument_name].is_a?(Array)
63
+ optional_arg[optional_argument_name].map { |v| ClassCoerce.new v }
64
+ else
65
+ ClassCoerce.new optional_arg[optional_argument_name]
65
66
  end
66
- optional_argument.validate_symbol! optional_arg_value
67
+ else
68
+ optional_arg[optional_argument_name]
69
+ end
67
70
 
68
- when :string
69
- unless optional_arg_value.is_a? String
70
- raise InvalidArgumentTypeError, "#{optional_arg_value} is not a String"
71
- end
72
- optional_argument.validate_string! optional_arg_value
71
+ if optional_arg_value.is_a?(Array) && !optional_argument.array
72
+ raise ArrayNotValidError, "An array was provided to an argument which does not accept an array of values"
73
+ end
73
74
 
74
- when :boolean
75
- unless optional_arg_value.is_a?(TrueClass) || optional_arg_value.is_a?(FalseClass)
76
- raise InvalidArgumentTypeError, "#{optional_arg_value} is not a boolean"
75
+ # to simplify the code, we always process the reset of the validations as an array, even
76
+ # if the argument is not of type array
77
+ values = optional_arg_value.is_a?(Array) ? optional_arg_value : [optional_arg_value]
78
+
79
+ values.each do |value|
80
+ case optional_argument.type
81
+ when :integer
82
+ unless value.is_a? Integer
83
+ raise InvalidArgumentTypeError, "`#{value}` is not an Integer"
84
+ end
85
+ optional_argument.validate_integer! value
86
+
87
+ when :symbol
88
+ unless value.is_a? Symbol
89
+ raise InvalidArgumentTypeError, "`#{value}` is not a Symbol"
90
+ end
91
+ optional_argument.validate_symbol! value
92
+
93
+ when :string
94
+ unless value.is_a? String
95
+ raise InvalidArgumentTypeError, "`#{value}` is not a String"
96
+ end
97
+ optional_argument.validate_string! value
98
+
99
+ when :boolean
100
+ unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
101
+ raise InvalidArgumentTypeError, "`#{value}` is not a boolean"
102
+ end
103
+ optional_argument.validate_boolean! value
104
+
105
+ when :class
106
+ unless value.is_a?(ClassCoerce)
107
+ raise InvalidArgumentTypeError, "`#{value}` is not a class coerce (String)"
108
+ end
109
+ optional_argument.validate_class! value
110
+
111
+ when :object
112
+ optional_argument.validate_object! value
113
+
114
+ else
115
+ raise InvalidArgumentTypeError, "The argument value `#{value}` is not a supported type"
77
116
  end
78
- optional_argument.validate_boolean! optional_arg_value
117
+ end
79
118
 
119
+ # The provided value appears valid for this argument, save the value.
120
+ #
121
+ # If the argument accepts an array of values, then automatically convert valid singular values
122
+ # into an array.
123
+ @arguments[optional_argument_name] = if optional_argument.array && !optional_arg_value.is_a?(Array)
124
+ [optional_arg_value]
80
125
  else
81
- raise InvalidArgumentTypeError, "The argument #{optional_arg_value} is not a supported type"
126
+ optional_arg_value
82
127
  end
83
128
 
84
- # the provided value appears valid for this argument, save the value
85
- @arguments[optional_argument_name] = optional_arg_value
86
-
87
129
  rescue => e
88
130
  raise e, "Error processing optional argument #{optional_argument_name}: #{e.message}", e.backtrace
89
131
  end
@@ -96,39 +138,78 @@ module DSLCompose
96
138
  argument_name = nil
97
139
  argument_name = required_argument.name
98
140
 
99
- arg = args[i]
100
- case required_argument.type
101
- when :integer
102
- unless arg.is_a? Integer
103
- raise InvalidArgumentTypeError, "#{arg} is not an Integer"
141
+ # the value for class types are wrapped in a ClassCoerce class so that they can be
142
+ # treated specially by the parser (it automatically converts them from a string name
143
+ # to the corresponding class, logic which doesn't happen here in case the class doesnt
144
+ # exist yet)
145
+ required_arg_value = if required_argument.type == :class
146
+ if args[i].is_a?(Array)
147
+ args[i].map { |v| ClassCoerce.new v }
148
+ else
149
+ ClassCoerce.new args[i]
104
150
  end
105
- required_argument.validate_integer! arg
151
+ else
152
+ args[i]
153
+ end
106
154
 
107
- when :symbol
108
- unless arg.is_a? Symbol
109
- raise InvalidArgumentTypeError, "#{arg} is not a Symbol"
110
- end
111
- required_argument.validate_symbol! arg
155
+ if required_arg_value.is_a?(Array) && !required_argument.array
156
+ raise ArrayNotValidError, "An array was provided to an argument which does not accept an array of values"
157
+ end
112
158
 
113
- when :string
114
- unless arg.is_a? String
115
- raise InvalidArgumentTypeError, "#{arg} is not a String"
116
- end
117
- required_argument.validate_string! arg
159
+ # to simplify the code, we always process the reset of the validations as an array, even
160
+ # if the argument is not of type array
161
+ values = required_arg_value.is_a?(Array) ? required_arg_value : [required_arg_value]
162
+
163
+ values.each do |value|
164
+ case required_argument.type
165
+ when :integer
166
+ unless value.is_a? Integer
167
+ raise InvalidArgumentTypeError, "`#{value}` is not an Integer"
168
+ end
169
+ required_argument.validate_integer! value
170
+
171
+ when :symbol
172
+ unless value.is_a? Symbol
173
+ raise InvalidArgumentTypeError, "`#{value}` is not a Symbol"
174
+ end
175
+ required_argument.validate_symbol! value
176
+
177
+ when :string
178
+ unless value.is_a? String
179
+ raise InvalidArgumentTypeError, "`#{value}` is not a String"
180
+ end
181
+ required_argument.validate_string! value
118
182
 
119
- when :boolean
120
- unless arg.is_a?(TrueClass) || arg.is_a?(FalseClass)
121
- raise InvalidArgumentTypeError, "#{arg} is not a boolean"
183
+ when :boolean
184
+ unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
185
+ raise InvalidArgumentTypeError, "`#{value}` is not a boolean"
186
+ end
187
+ required_argument.validate_boolean! value
188
+
189
+ when :class
190
+ unless value.is_a?(ClassCoerce)
191
+ raise InvalidArgumentTypeError, "`#{value}` is not a class coerce (String)"
192
+ end
193
+ required_argument.validate_class! value
194
+
195
+ when :object
196
+ required_argument.validate_object! value
197
+
198
+ else
199
+ raise InvalidArgumentTypeError, "The argument `#{value}` is not a supported type"
122
200
  end
123
- required_argument.validate_boolean! arg
201
+ end
124
202
 
203
+ # The provided value appears valid for this argument, save the value.
204
+ #
205
+ # If the argument accepts an array of values, then automatically convert valid singular values
206
+ # into an array.
207
+ @arguments[argument_name] = if required_argument.array && !required_arg_value.is_a?(Array)
208
+ [required_arg_value]
125
209
  else
126
- raise InvalidArgumentTypeError, "The argument #{arg} is not a supported type"
210
+ required_arg_value
127
211
  end
128
212
 
129
- # the provided value appears valid for this argument, save the value
130
- @arguments[required_argument.name] = arg
131
-
132
213
  rescue => e
133
214
  raise e, "Error processing required argument #{argument_name}: #{e.message}", e.backtrace
134
215
  end
@@ -77,7 +77,9 @@ module DSLCompose
77
77
  # add any arguments that were provided to the method call
78
78
  method_call.arguments.arguments.each do |name, value|
79
79
  if BlockArguments.accepts_argument?(name, &block)
80
- args[name] = value
80
+ # if this value is a ClassCoerce object, then convert it from its original
81
+ # string value to a class
82
+ args[name] = value.is_a?(ClassCoerce) ? value.to_class : value
81
83
  end
82
84
  end
83
85
 
@@ -73,7 +73,9 @@ module DSLCompose
73
73
  # add any arguments that were provided to the DSL
74
74
  dsl_execution.arguments.arguments.each do |name, value|
75
75
  if BlockArguments.accepts_argument?(name, &block)
76
- args[name] = value
76
+ # if this value is a ClassCoerce object, then convert it from its original
77
+ # string value to a class
78
+ args[name] = value.is_a?(ClassCoerce) ? value.to_class : value
77
79
  end
78
80
  end
79
81
  # set the dsl_execution in an instance variable so that method calls to `for_method`
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DSLCompose
4
+ # This module is used to store shared configuration blocks which can be imported and
5
+ # used within your base or method dsl configuration blocks.
6
+ module SharedConfiguration
7
+ class SharedConfigurationAlreadyExistsError < StandardError
8
+ end
9
+
10
+ class SharedConfigurationDoesNotExistError < StandardError
11
+ end
12
+
13
+ class InvalidSharedConfigurationNameError < StandardError
14
+ end
15
+
16
+ class NoBlockProvidedError < StandardError
17
+ end
18
+
19
+ # takes a name and a block and stores it in the shared_configuration hash
20
+ # if a block with this name already exists, it raises an error
21
+ def self.add name, &block
22
+ raise InvalidSharedConfigurationNameError unless name.is_a?(Symbol)
23
+ raise SharedConfigurationAlreadyExistsError if @shared_configuration&.key?(name)
24
+ raise NoBlockProvidedError if block.nil?
25
+
26
+ @shared_configuration ||= {}
27
+ @shared_configuration[name] = block
28
+ end
29
+
30
+ # takes a name and returns the block stored in the shared_configuration hash
31
+ # if a block with this name does not exist, it raises an error
32
+ def self.get name
33
+ raise InvalidSharedConfigurationNameError unless name.is_a?(Symbol)
34
+ raise SharedConfigurationDoesNotExistError unless @shared_configuration&.key?(name)
35
+
36
+ @shared_configuration[name]
37
+ end
38
+
39
+ # clears the shared_configuration hash, this is typically used from the test suite
40
+ def self.clear
41
+ @shared_configuration = {}
42
+ end
43
+ end
44
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DSLCompose
4
- VERSION = "1.9.1"
4
+ VERSION = "1.11.0"
5
5
  end
data/lib/dsl_compose.rb CHANGED
@@ -8,6 +8,7 @@ require "dsl_compose/dsl/arguments/argument/format_validation"
8
8
  require "dsl_compose/dsl/arguments/argument/greater_than_or_equal_to_validation"
9
9
  require "dsl_compose/dsl/arguments/argument/greater_than_validation"
10
10
  require "dsl_compose/dsl/arguments/argument/in_validation"
11
+ require "dsl_compose/dsl/arguments/argument/is_a_validation"
11
12
  require "dsl_compose/dsl/arguments/argument/length_validation"
12
13
  require "dsl_compose/dsl/arguments/argument/less_than_or_equal_to_validation"
13
14
  require "dsl_compose/dsl/arguments/argument/less_than_validation"
@@ -41,6 +42,10 @@ require "dsl_compose/parser"
41
42
 
42
43
  require "dsl_compose/composer"
43
44
 
45
+ require "dsl_compose/class_coerce"
46
+
47
+ require "dsl_compose/shared_configuration"
48
+
44
49
  require "dsl_compose/dsls"
45
50
 
46
51
  module DSLCompose
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dsl_compose
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.1
4
+ version: 1.11.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-11 00:00:00.000000000 Z
11
+ date: 2023-07-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Ruby gem to add dynamic DSLs to classes. DSLs are added to classes by
14
14
  including the DSLCompose module, and then calling the add_dsl singleton method within
@@ -24,6 +24,7 @@ files:
24
24
  - LICENSE.txt
25
25
  - README.md
26
26
  - lib/dsl_compose.rb
27
+ - lib/dsl_compose/class_coerce.rb
27
28
  - lib/dsl_compose/composer.rb
28
29
  - lib/dsl_compose/dsl.rb
29
30
  - lib/dsl_compose/dsl/arguments.rb
@@ -35,6 +36,7 @@ files:
35
36
  - lib/dsl_compose/dsl/arguments/argument/greater_than_validation.rb
36
37
  - lib/dsl_compose/dsl/arguments/argument/in_validation.rb
37
38
  - lib/dsl_compose/dsl/arguments/argument/interpreter.rb
39
+ - lib/dsl_compose/dsl/arguments/argument/is_a_validation.rb
38
40
  - lib/dsl_compose/dsl/arguments/argument/length_validation.rb
39
41
  - lib/dsl_compose/dsl/arguments/argument/less_than_or_equal_to_validation.rb
40
42
  - lib/dsl_compose/dsl/arguments/argument/less_than_validation.rb
@@ -56,6 +58,7 @@ files:
56
58
  - lib/dsl_compose/parser/for_children_of_parser.rb
57
59
  - lib/dsl_compose/parser/for_children_of_parser/for_dsl_parser.rb
58
60
  - lib/dsl_compose/parser/for_children_of_parser/for_dsl_parser/for_method_parser.rb
61
+ - lib/dsl_compose/shared_configuration.rb
59
62
  - lib/dsl_compose/version.rb
60
63
  homepage:
61
64
  licenses: