dsl_compose 2.1.1 → 2.2.1

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: 826d148f5440924eeea1a56699ec7f6a421dcf5fe273012e7e9cf9010ab4cb66
4
- data.tar.gz: 0fa06d0fcf99bea843da3b3b5cb66f196be88a923287ba4df64459e6289f7054
3
+ metadata.gz: dc5d05054343d31af8700ec10104ef0040615583c026d5588354888092670e63
4
+ data.tar.gz: a211ab077787f947eb2337a727c516e600903b6ec5dd4dc4650d3cb16aa264bc
5
5
  SHA512:
6
- metadata.gz: c4bcce09e0c5b3028c97ac09dbd16a6481ed8514857e7bcaecbbe7b40aebec22b8d7b4220f299380363dd9b87de9c0585fa456d8c70c031e967d3e6048711b60
7
- data.tar.gz: 20eb3288cafb32aafddc8efe78e2e8fba5cf088c1896b5a9e82eb42e21c63c84d6e2536888d5e938f9f4b9bc80d064bfb5e95ca2fdb410316707f0362e0bf6cf
6
+ metadata.gz: 438b429f3fd729f655b474c9d23a4224e41e66d6bcbfd32bf227607772a83c54a5400cb7e5dbdc947a101240ee43f8656fb1f7c4798e0a3c4218679090db00d3
7
+ data.tar.gz: 8717ba33401dcc579de9de6bb6132263ba1737e87b8820874cc5e1d161651bdffe1481d3f676fb10d1ffef8da254eaaea95a83e1c1bccc58cc16b9511428efc5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.2.1](https://github.com/craigulliott/dsl_compose/compare/v2.2.0...v2.2.1) (2023-07-27)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * last_execution was raising error instead of returning nil when no executions were found ([bedef1e](https://github.com/craigulliott/dsl_compose/commit/bedef1ec606801a4507ce77c39a33d14cb79818f))
9
+
10
+ ## [2.2.0](https://github.com/craigulliott/dsl_compose/compare/v2.1.1...v2.2.0) (2023-07-27)
11
+
12
+
13
+ ### Features
14
+
15
+ * Added a ReaderBase which can be extended to create custom reader classes. Also added dsl_used?, dsl_used_on_ancestors? and dsl_used_on_class_or_ancestors? helper methods to the Reader class ([6507e4a](https://github.com/craigulliott/dsl_compose/commit/6507e4a082c9a0d7e63c580a17bcb8eb2bd940ea))
16
+
3
17
  ## [2.1.1](https://github.com/craigulliott/dsl_compose/compare/v2.1.0...v2.1.1) (2023-07-26)
4
18
 
5
19
 
data/README.md CHANGED
@@ -339,10 +339,6 @@ reader = DSLCompose::Reader.new MyClass, :my_dsl
339
339
  # If no execution of the DSL is found, then nil will be returned
340
340
  execution = reader.last_execution
341
341
 
342
- # `execution.arguments` returns an ArgumentsReader object which allows access
343
- # via dot notation to to any argument values provided to the DSL
344
- execution.arguments.my_dsl_argument # returns the value provided for the argument, or nil
345
-
346
342
  # `execution.method_called?` will return true if the method with the provided
347
343
  # name was called, if a method with this name does exist, but was not called
348
344
  # then false will be returned. If a method with this name does not exist, then
@@ -372,7 +368,9 @@ execution.my_dsl_method.each do |arguments|
372
368
  end
373
369
 
374
370
  # Returns an array of ExecutionReaders to represent each time the DSL was used
375
- # on ancestors of the provided class.
371
+ # on the provided class.
372
+ executions = reader.executions
373
+
376
374
  # Returns an array of ExecutionReaders to represent each time the DSL was used
377
375
  # on the ancestors of the provided class, but not on the provided class itself.
378
376
  # The executions will be returned in the order they were executed, which is the
@@ -386,6 +384,106 @@ executions = reader.ancestor_executions
386
384
  # and if the DSL was used more than once on a class then the order they were used.
387
385
  executions = reader.all_executions
388
386
 
387
+ # Returns true if dsl has been executed once or more on the provided class,
388
+ # otherwise returns false.
389
+ was_used = reader.dsl_used?
390
+
391
+ # Returns true if dsl has been executed once or more on one of the ancestors
392
+ # of the provided class, otherwise returns false.
393
+ was_used = reader.dsl_used_on_ancestors?
394
+
395
+ # Returns true if dsl has been executed once or more on the provided class or
396
+ # any of its ancestors, otherwise returns false.
397
+ was_used = reader.dsl_used_on_class_or_ancestors?
398
+
399
+ # `execution.arguments` returns an ArgumentsReader object which allows access
400
+ # via dot notation to to any argument values provided to the DSL
401
+ execution.arguments.my_dsl_argument # returns the value provided for the argument, or nil
402
+ ```
403
+
404
+ A ReaderBase class is also provided. You can extend this class to create your own Reader objects and provide a much cleaner interface to your specific DSLs.
405
+
406
+ ```ruby
407
+ # This is an example DSL for configuring which database and schema should be used
408
+ # by classes which extend a BaseModel (it's from a hypothetical ORM).
409
+ class BaseModel
410
+ # define a DSL which can be used on descendants of this class
411
+ # to determine which database should be used
412
+ define_dsl :database_configuration do
413
+ requires :server_type, :symbol do
414
+ validate_in [:postgres, :mysql]
415
+ end
416
+ requires :server_name, :symbol
417
+ optional :database_name, :symbol
418
+ end
419
+ # define a DSL to set the schema which should be used
420
+ define_dsl :schema do
421
+ requires :schema_name, :symbol
422
+ end
423
+ end
424
+
425
+ # A hypothetical model which extends BaseModel and uses this DSL
426
+ class User < BaseModel
427
+ # Use the primary postgres server and the default database_name (because
428
+ # we are not using the optional `database_name: :foo` argument).
429
+ database_configuration :postgres, :primary
430
+ # Persist this models data in the `users` schema.
431
+ schema :users
432
+ end
433
+
434
+ # An example reader which could be created to provide a more concise
435
+ # interface to this DSL.
436
+ # Because this DSL Reader is named DatabaseConfigurationDSLReader it
437
+ # will automatically refer to the dsl named :database_configuration.
438
+ class DatabaseConfigurationDSLReader < DSLCompose::ReaderBase
439
+ # The three methods below provide a more concise access to the DSLs
440
+ # arguments. If the DSL was never used on the provided class, or any
441
+ # of it's ancestors, then an error will be raised. This error will
442
+ # be raised because we are using `last_execution!` instead of `last_execution`.
443
+ def server_type
444
+ last_execution!.arguments.server_type
445
+ end
446
+
447
+ def server_name
448
+ last_execution!.arguments.server_name
449
+ end
450
+
451
+ def database_name
452
+ last_execution!.arguments.database_name
453
+ end
454
+
455
+ # Returns true or false, depending on if the optional database_name
456
+ # attribute was used when executing the DSL. If the DSL was never
457
+ # used on the provided class, or any of it's ancestors, then an error will
458
+ # be raised (because of the bang method).
459
+ def has_database_name?
460
+ last_execution!.arguments.database_name != nil
461
+ end
462
+
463
+ # This method is provided as an example of how to reference other DSLs within
464
+ # your reader.
465
+ def schema_name
466
+ last_execution_of_schema&.arguments&.schema_name || :public
467
+ end
468
+
469
+ private
470
+
471
+ # This method is used by the schema_name method above, and is included as an
472
+ # example of how to reference other DSLs within your Reader.
473
+ def last_execution_of_schema
474
+ # Note that there is no bang method here (no "!" after last_execution), so it
475
+ # will return nil if the DSL was not used.
476
+ @schema_reader ||= DSLCompose::Reader.new(@base_class, :schema).last_execution
477
+ end
478
+ end
479
+
480
+ # Use our DatabaseConfigurationDSLReader when parsing this class to
481
+ # enjoy a more concise API for accessing our DSL values
482
+ reader = DatabaseConfigurationDSLReader.new(User)
483
+ reader.server_type # :postgres
484
+ reader.has_database_name? # false
485
+ reader.schema_name # :users
486
+
389
487
  ```
390
488
 
391
489
 
@@ -11,6 +11,9 @@ module DSLCompose
11
11
  class DSLNotFound < StandardError
12
12
  end
13
13
 
14
+ class NoDSLExecutionFound < StandardError
15
+ end
16
+
14
17
  # given a class and the DSL name, finds and creates a reference to the DSL
15
18
  # and the ancestor class where the DSL was originally defined
16
19
  def initialize klass, dsl_name
@@ -42,16 +45,44 @@ module DSLCompose
42
45
  end
43
46
  end
44
47
 
48
+ # Returns true if dsl has been executed once or more on the provided class,
49
+ # otherwise returns false.
50
+ def dsl_used?
51
+ executions.any?
52
+ end
53
+
54
+ # Returns true if dsl has been executed once or more on one of the ancestors
55
+ # of the provided class, otherwise returns false.
56
+ def dsl_used_on_ancestors?
57
+ ancestor_executions.any?
58
+ end
59
+
60
+ # Returns true if dsl has been executed once or more on the provided class or
61
+ # any of its ancestors, otherwise returns false.
62
+ def dsl_used_on_class_or_ancestors?
63
+ all_executions.any?
64
+ end
65
+
45
66
  # Returns an ExecutionReader class which exposes a simple API to access the
46
67
  # arguments, methods and method arguments provided when using this DSL.
47
68
  #
48
- # If the dsl has been executed once or more on the provided class, then
49
- # the last (most recent) execution will be returned. If the DSL was not
69
+ # If the dsl has been executed once or more on the provided class, then a reader
70
+ # for the last (most recent) execution will be returned. If the DSL was not
50
71
  # executed on the provided class, then we traverse up the classes ancestors
51
72
  # and look for the last time it was executed on each ancestor.
52
73
  # If no execution of the DSL is found, then nil will be returned
53
74
  def last_execution
54
- ExecutionReader.new(@dsl_defining_class.dsls.get_last_dsl_execution(@klass, @dsl_name))
75
+ execution = @dsl_defining_class.dsls.get_last_dsl_execution(@klass, @dsl_name)
76
+ if execution.nil?
77
+ nil
78
+ else
79
+ ExecutionReader.new execution
80
+ end
81
+ end
82
+
83
+ # A wrapper for last_execution which raises an error if no execution exists
84
+ def last_execution!
85
+ last_execution || (raise NoDSLExecutionFound, "No execution of the `#{@dsl_name}` dsl was found on `#{@klass}` or any of its ancestors")
55
86
  end
56
87
 
57
88
  # Returns an array of ExecutionReaders to represent each time the DSL was used
@@ -0,0 +1,64 @@
1
+ module DSLCompose
2
+ # This class provides a skeleton for creating your own DSL readers.
3
+ #
4
+ # All classes which extend from this base class must follow a strict naming convention. The class name
5
+ # must be the camelcased form of the DSL name, followed by the string "DSLReader". For example, a reader
6
+ # for a DLS named `:foo_bar` must have the class name `FooBarDSLReader`, as seen below
7
+ #
8
+ # class FooBarDSLReader < DSLCompose::ReaderBase
9
+ # # ...
10
+ # end
11
+ class ReaderBase
12
+ attr_reader :base_class
13
+ attr_reader :dsl_name
14
+ attr_reader :reader
15
+
16
+ def initialize base_class
17
+ @base_class = base_class
18
+ # get the DSL name from the class name
19
+ @dsl_name = dsl_name_from_class_name self.class
20
+ # create the reader
21
+ @reader = DSLCompose::Reader.new(base_class, @dsl_name)
22
+ end
23
+
24
+ private
25
+
26
+ def dsl_name_from_class_name reader_class
27
+ camelcased = reader_class.name.split("::").last.gsub(/DSLReader\Z/, "")
28
+ underscored = camelcased.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2').gsub(/([a-z\d])([A-Z])/, '\1_\2')
29
+ underscored.downcase.to_sym
30
+ end
31
+
32
+ def dsl_used?
33
+ @reader.dsl_used?
34
+ end
35
+
36
+ def dsl_used_on_ancestors?
37
+ @reader.dsl_used_on_ancestors?
38
+ end
39
+
40
+ def dsl_used_on_class_or_ancestors?
41
+ @reader.dsl_used_on_class_or_ancestors?
42
+ end
43
+
44
+ def last_execution
45
+ @reader.last_execution
46
+ end
47
+
48
+ def last_execution!
49
+ @reader.last_execution!
50
+ end
51
+
52
+ def executions
53
+ @reader.executions
54
+ end
55
+
56
+ def ancestor_executions
57
+ @reader.ancestor_executions
58
+ end
59
+
60
+ def all_executions
61
+ @reader.all_executions
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DSLCompose
4
- VERSION = "2.1.1"
4
+ VERSION = "2.2.1"
5
5
  end
data/lib/dsl_compose.rb CHANGED
@@ -32,6 +32,8 @@ require "dsl_compose/reader"
32
32
  require "dsl_compose/reader/execution_reader"
33
33
  require "dsl_compose/reader/execution_reader/arguments_reader"
34
34
 
35
+ require "dsl_compose/reader_base"
36
+
35
37
  require "dsl_compose/interpreter/execution/method_calls/method_call"
36
38
  require "dsl_compose/interpreter/execution/method_calls"
37
39
  require "dsl_compose/interpreter/execution/arguments"
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: 2.1.1
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Craig Ulliott
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-26 00:00:00.000000000 Z
11
+ date: 2023-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: class_spec_helper
@@ -77,15 +77,16 @@ files:
77
77
  - lib/dsl_compose/reader.rb
78
78
  - lib/dsl_compose/reader/execution_reader.rb
79
79
  - lib/dsl_compose/reader/execution_reader/arguments_reader.rb
80
+ - lib/dsl_compose/reader_base.rb
80
81
  - lib/dsl_compose/shared_configuration.rb
81
82
  - lib/dsl_compose/version.rb
82
- homepage:
83
+ homepage:
83
84
  licenses:
84
85
  - MIT
85
86
  metadata:
86
87
  source_code_uri: https://github.com/craigulliott/dsl_compose/
87
88
  changelog_uri: https://github.com/craigulliott/dsl_compose/blob/main/CHANGELOG.md
88
- post_install_message:
89
+ post_install_message:
89
90
  rdoc_options: []
90
91
  require_paths:
91
92
  - lib
@@ -101,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
102
  version: '0'
102
103
  requirements: []
103
104
  rubygems_version: 3.3.26
104
- signing_key:
105
+ signing_key:
105
106
  specification_version: 4
106
107
  summary: Ruby gem to add dynamic DSLs to classes
107
108
  test_files: []