dsl_compose 1.9.1 → 1.11.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
  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: