light-services 2.2.1 → 3.0.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.github/config/rubocop_linter_action.yml +4 -4
  3. data/.github/workflows/ci.yml +12 -12
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +77 -7
  6. data/CHANGELOG.md +23 -0
  7. data/CLAUDE.md +139 -0
  8. data/Gemfile +16 -11
  9. data/Gemfile.lock +53 -27
  10. data/README.md +76 -13
  11. data/docs/arguments.md +267 -0
  12. data/docs/best-practices.md +153 -0
  13. data/docs/callbacks.md +476 -0
  14. data/docs/concepts.md +80 -0
  15. data/docs/configuration.md +168 -0
  16. data/docs/context.md +128 -0
  17. data/docs/crud.md +525 -0
  18. data/docs/errors.md +250 -0
  19. data/docs/generators.md +250 -0
  20. data/docs/outputs.md +135 -0
  21. data/docs/pundit-authorization.md +320 -0
  22. data/docs/quickstart.md +134 -0
  23. data/docs/readme.md +100 -0
  24. data/docs/recipes.md +14 -0
  25. data/docs/service-rendering.md +222 -0
  26. data/docs/steps.md +337 -0
  27. data/docs/summary.md +19 -0
  28. data/docs/testing.md +549 -0
  29. data/lib/generators/light_services/install/USAGE +15 -0
  30. data/lib/generators/light_services/install/install_generator.rb +41 -0
  31. data/lib/generators/light_services/install/templates/application_service.rb.tt +8 -0
  32. data/lib/generators/light_services/install/templates/application_service_spec.rb.tt +7 -0
  33. data/lib/generators/light_services/install/templates/initializer.rb.tt +30 -0
  34. data/lib/generators/light_services/service/USAGE +21 -0
  35. data/lib/generators/light_services/service/service_generator.rb +68 -0
  36. data/lib/generators/light_services/service/templates/service.rb.tt +48 -0
  37. data/lib/generators/light_services/service/templates/service_spec.rb.tt +40 -0
  38. data/lib/light/services/base.rb +23 -113
  39. data/lib/light/services/callbacks.rb +103 -0
  40. data/lib/light/services/collection.rb +97 -0
  41. data/lib/light/services/concerns/execution.rb +76 -0
  42. data/lib/light/services/concerns/parent_service.rb +34 -0
  43. data/lib/light/services/concerns/state_management.rb +30 -0
  44. data/lib/light/services/config.rb +4 -18
  45. data/lib/light/services/constants.rb +97 -0
  46. data/lib/light/services/dsl/arguments_dsl.rb +84 -0
  47. data/lib/light/services/dsl/outputs_dsl.rb +80 -0
  48. data/lib/light/services/dsl/steps_dsl.rb +205 -0
  49. data/lib/light/services/dsl/validation.rb +132 -0
  50. data/lib/light/services/exceptions.rb +7 -2
  51. data/lib/light/services/messages.rb +19 -31
  52. data/lib/light/services/rspec/matchers/define_argument.rb +174 -0
  53. data/lib/light/services/rspec/matchers/define_output.rb +147 -0
  54. data/lib/light/services/rspec/matchers/define_step.rb +225 -0
  55. data/lib/light/services/rspec/matchers/execute_step.rb +230 -0
  56. data/lib/light/services/rspec/matchers/have_error_on.rb +148 -0
  57. data/lib/light/services/rspec/matchers/have_warning_on.rb +148 -0
  58. data/lib/light/services/rspec/matchers/trigger_callback.rb +138 -0
  59. data/lib/light/services/rspec.rb +15 -0
  60. data/lib/light/services/settings/field.rb +86 -0
  61. data/lib/light/services/settings/step.rb +31 -16
  62. data/lib/light/services/utils.rb +38 -0
  63. data/lib/light/services/version.rb +1 -1
  64. data/lib/light/services.rb +2 -0
  65. data/light-services.gemspec +6 -8
  66. metadata +54 -26
  67. data/lib/light/services/class_based_collection/base.rb +0 -86
  68. data/lib/light/services/class_based_collection/mount.rb +0 -33
  69. data/lib/light/services/collection/arguments.rb +0 -34
  70. data/lib/light/services/collection/base.rb +0 -59
  71. data/lib/light/services/collection/outputs.rb +0 -16
  72. data/lib/light/services/settings/argument.rb +0 -68
  73. data/lib/light/services/settings/output.rb +0 -34
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Unified settings class for arguments and outputs
4
+ module Light
5
+ module Services
6
+ module Settings
7
+ class Field
8
+ attr_reader :name, :default_exists, :default, :context, :optional
9
+
10
+ def initialize(name, service_class, opts = {})
11
+ @name = name
12
+ @service_class = service_class
13
+ @field_type = opts.delete(:field_type) || :argument
14
+
15
+ @type = opts.delete(:type)
16
+ @context = opts.delete(:context)
17
+ @default_exists = opts.key?(:default)
18
+ @default = opts.delete(:default)
19
+ @optional = opts.delete(:optional)
20
+
21
+ define_methods
22
+ end
23
+
24
+ # Validate and optionally coerce the value
25
+ # Returns the (possibly coerced) value
26
+ def validate_type!(value)
27
+ return value unless @type
28
+
29
+ if dry_type?(@type)
30
+ coerce_and_validate_dry_type!(value)
31
+ else
32
+ validate_ruby_type!(value)
33
+ value
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # Check if the type is a dry-types type
40
+ def dry_type?(type)
41
+ return false unless defined?(Dry::Types::Type)
42
+
43
+ type.is_a?(Dry::Types::Type)
44
+ end
45
+
46
+ # Validate and coerce value against dry-types
47
+ # Returns the coerced value
48
+ def coerce_and_validate_dry_type!(value)
49
+ @type[value]
50
+ rescue Dry::Types::ConstraintError, Dry::Types::CoercionError => e
51
+ raise Light::Services::ArgTypeError,
52
+ "#{@service_class} #{@field_type} `#{@name}` #{e.message}"
53
+ end
54
+
55
+ # Validate value against Ruby class types
56
+ def validate_ruby_type!(value)
57
+ return if [*@type].any? { |type| value.is_a?(type) }
58
+
59
+ raise Light::Services::ArgTypeError, type_error_message(value)
60
+ end
61
+
62
+ def type_error_message(value)
63
+ expected_types = [*@type].map(&:to_s).join(" or ")
64
+ "#{@service_class} #{@field_type} `#{@name}` must be #{expected_types}, \" \\
65
+ \"but got #{value.class} with value: #{value.inspect}"
66
+ end
67
+
68
+ def define_methods
69
+ name = @name
70
+ collection_instance_var = :"@#{@field_type}s"
71
+
72
+ @service_class.define_method(@name) { instance_variable_get(collection_instance_var).get(name) }
73
+ @service_class.define_method(:"#{@name}?") { !!instance_variable_get(collection_instance_var).get(name) }
74
+ @service_class.define_method(:"#{@name}=") do |value|
75
+ instance_variable_get(collection_instance_var).set(name, value)
76
+ end
77
+ @service_class.send(:private, "#{@name}=")
78
+ end
79
+ end
80
+
81
+ # Aliases for backwards compatibility
82
+ Argument = Field
83
+ Output = Field
84
+ end
85
+ end
86
+ end
@@ -17,33 +17,48 @@ module Light
17
17
  @always = opts[:always]
18
18
 
19
19
  if @if && @unless
20
- raise Light::Services::TwoConditions, "#{service_class} `if` and `unless` cannot be specified " \
21
- "for the step `#{name}` at the same time"
20
+ raise Light::Services::Error, "#{service_class} `if` and `unless` cannot be specified " \
21
+ "for the step `#{name}` at the same time"
22
22
  end
23
23
  end
24
24
 
25
- def run(instance, benchmark: false)
25
+ def run(instance) # rubocop:disable Naming/PredicateMethod
26
26
  return false unless run?(instance)
27
27
 
28
- if instance.respond_to?(name, true)
29
- if benchmark
30
- time = Benchmark.ms do
31
- instance.send(name)
32
- end
28
+ unless instance.respond_to?(name, true)
29
+ available_steps = @service_class.steps.keys.join(", ")
30
+ raise Light::Services::Error,
31
+ "Step method `#{name}` is not defined in #{@service_class}. " \
32
+ "Defined steps: [#{available_steps}]"
33
+ end
33
34
 
34
- instance.log "⏱️ Step #{name} took #{time}ms"
35
- else
36
- instance.send(name)
37
- end
35
+ execute_with_callbacks(instance)
36
+ true
37
+ end
38
38
 
39
- true
39
+ private
40
+
41
+ def execute_with_callbacks(instance)
42
+ errors_count_before = instance.errors.count
43
+
44
+ instance.run_callbacks(:before_step_run, instance, name)
45
+
46
+ instance.run_callbacks(:around_step_run, instance, name) do
47
+ instance.send(name)
48
+ end
49
+
50
+ instance.run_callbacks(:after_step_run, instance, name)
51
+
52
+ if instance.errors.count > errors_count_before
53
+ instance.run_callbacks(:on_step_failure, instance, name)
40
54
  else
41
- raise Light::Services::NoStepError, "Cannot find step `#{name}` in service `#{@service_class}`"
55
+ instance.run_callbacks(:on_step_success, instance, name)
42
56
  end
57
+ rescue StandardError => e
58
+ instance.run_callbacks(:on_step_crash, instance, name, e)
59
+ raise e
43
60
  end
44
61
 
45
- private
46
-
47
62
  def run?(instance)
48
63
  return false if instance.done?
49
64
 
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Light
4
+ module Services
5
+ # Utility module providing helper methods for the Light Services library
6
+ module Utils
7
+ module_function
8
+
9
+ # Creates a deep copy of an object to prevent mutation of shared references.
10
+ #
11
+ # @param object [Object] the object to duplicate
12
+ # @return [Object] a deep copy of the object
13
+ #
14
+ # @example Deep duping a hash
15
+ # original = { a: { b: 1 } }
16
+ # copy = Utils.deep_dup(original)
17
+ # copy[:a][:b] = 2
18
+ # original[:a][:b] # => 1
19
+ #
20
+ # @example Deep duping an array
21
+ # original = [[1, 2], [3, 4]]
22
+ # copy = Utils.deep_dup(original)
23
+ # copy[0] << 5
24
+ # original[0] # => [1, 2]
25
+ #
26
+ def deep_dup(object)
27
+ # Use ActiveSupport's deep_dup if available (preferred for Rails apps)
28
+ return object.deep_dup if object.respond_to?(:deep_dup)
29
+
30
+ # Fallback to Marshal for objects that support serialization
31
+ Marshal.load(Marshal.dump(object))
32
+ rescue TypeError
33
+ # Last resort: use dup if available, otherwise return original
34
+ object.respond_to?(:dup) ? object.dup : object
35
+ end
36
+ end
37
+ end
38
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Light
4
4
  module Services
5
- VERSION = "2.2.1"
5
+ VERSION = "3.0.0"
6
6
  end
7
7
  end
@@ -3,6 +3,8 @@
3
3
  require "light/services/config"
4
4
  require "light/services/version"
5
5
  require "light/services/exceptions"
6
+ require "light/services/utils"
7
+ require "light/services/callbacks"
6
8
  require "light/services/base"
7
9
 
8
10
  module Light
@@ -8,11 +8,11 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Andrew Kodkod"]
9
9
  spec.email = ["andrew@kodkod.me"]
10
10
 
11
- spec.summary = "Robust service architecture for Ruby frameworks"
12
- spec.description = "Robust service architecture for Ruby frameworks"
11
+ spec.summary = "Robust service architecture for Ruby/Rails applications"
12
+ spec.description = "Light Services is a simple yet powerful way to organize business logic in Ruby applications. Build services that are easy to test, maintain, and understand." # rubocop:disable Layout/LineLength
13
13
  spec.homepage = "https://light-services-docs.vercel.app/"
14
14
  spec.license = "MIT"
15
- spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0.0")
16
16
 
17
17
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
18
18
 
@@ -26,10 +26,8 @@ Gem::Specification.new do |spec|
26
26
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
27
  end
28
28
 
29
- spec.bindir = "exe"
30
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
- spec.require_paths = ["lib"]
29
+ spec.bindir = "exe"
30
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
31
+ spec.require_paths = ["lib"]
32
32
  spec.metadata["rubygems_mfa_required"] = "true"
33
-
34
- spec.add_dependency "benchmark", ">= 0.5"
35
33
  end
metadata CHANGED
@@ -1,29 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: light-services
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kodkod
8
8
  bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
- dependencies:
12
- - !ruby/object:Gem::Dependency
13
- name: benchmark
14
- requirement: !ruby/object:Gem::Requirement
15
- requirements:
16
- - - ">="
17
- - !ruby/object:Gem::Version
18
- version: '0.5'
19
- type: :runtime
20
- prerelease: false
21
- version_requirements: !ruby/object:Gem::Requirement
22
- requirements:
23
- - - ">="
24
- - !ruby/object:Gem::Version
25
- version: '0.5'
26
- description: Robust service architecture for Ruby frameworks
11
+ dependencies: []
12
+ description: Light Services is a simple yet powerful way to organize business logic
13
+ in Ruby applications. Build services that are easy to test, maintain, and understand.
27
14
  email:
28
15
  - andrew@kodkod.me
29
16
  executables: []
@@ -38,6 +25,7 @@ files:
38
25
  - ".rubocop.yml"
39
26
  - ".ruby-version"
40
27
  - CHANGELOG.md
28
+ - CLAUDE.md
41
29
  - CODE_OF_CONDUCT.md
42
30
  - Gemfile
43
31
  - Gemfile.lock
@@ -46,21 +34,61 @@ files:
46
34
  - Rakefile
47
35
  - bin/console
48
36
  - bin/setup
37
+ - docs/arguments.md
38
+ - docs/best-practices.md
39
+ - docs/callbacks.md
40
+ - docs/concepts.md
41
+ - docs/configuration.md
42
+ - docs/context.md
43
+ - docs/crud.md
44
+ - docs/errors.md
45
+ - docs/generators.md
46
+ - docs/outputs.md
47
+ - docs/pundit-authorization.md
48
+ - docs/quickstart.md
49
+ - docs/readme.md
50
+ - docs/recipes.md
51
+ - docs/service-rendering.md
52
+ - docs/steps.md
53
+ - docs/summary.md
54
+ - docs/testing.md
55
+ - lib/generators/light_services/install/USAGE
56
+ - lib/generators/light_services/install/install_generator.rb
57
+ - lib/generators/light_services/install/templates/application_service.rb.tt
58
+ - lib/generators/light_services/install/templates/application_service_spec.rb.tt
59
+ - lib/generators/light_services/install/templates/initializer.rb.tt
60
+ - lib/generators/light_services/service/USAGE
61
+ - lib/generators/light_services/service/service_generator.rb
62
+ - lib/generators/light_services/service/templates/service.rb.tt
63
+ - lib/generators/light_services/service/templates/service_spec.rb.tt
49
64
  - lib/light/services.rb
50
65
  - lib/light/services/base.rb
51
66
  - lib/light/services/base_with_context.rb
52
- - lib/light/services/class_based_collection/base.rb
53
- - lib/light/services/class_based_collection/mount.rb
54
- - lib/light/services/collection/arguments.rb
55
- - lib/light/services/collection/base.rb
56
- - lib/light/services/collection/outputs.rb
67
+ - lib/light/services/callbacks.rb
68
+ - lib/light/services/collection.rb
69
+ - lib/light/services/concerns/execution.rb
70
+ - lib/light/services/concerns/parent_service.rb
71
+ - lib/light/services/concerns/state_management.rb
57
72
  - lib/light/services/config.rb
73
+ - lib/light/services/constants.rb
74
+ - lib/light/services/dsl/arguments_dsl.rb
75
+ - lib/light/services/dsl/outputs_dsl.rb
76
+ - lib/light/services/dsl/steps_dsl.rb
77
+ - lib/light/services/dsl/validation.rb
58
78
  - lib/light/services/exceptions.rb
59
79
  - lib/light/services/message.rb
60
80
  - lib/light/services/messages.rb
61
- - lib/light/services/settings/argument.rb
62
- - lib/light/services/settings/output.rb
81
+ - lib/light/services/rspec.rb
82
+ - lib/light/services/rspec/matchers/define_argument.rb
83
+ - lib/light/services/rspec/matchers/define_output.rb
84
+ - lib/light/services/rspec/matchers/define_step.rb
85
+ - lib/light/services/rspec/matchers/execute_step.rb
86
+ - lib/light/services/rspec/matchers/have_error_on.rb
87
+ - lib/light/services/rspec/matchers/have_warning_on.rb
88
+ - lib/light/services/rspec/matchers/trigger_callback.rb
89
+ - lib/light/services/settings/field.rb
63
90
  - lib/light/services/settings/step.rb
91
+ - lib/light/services/utils.rb
64
92
  - lib/light/services/version.rb
65
93
  - light-services.gemspec
66
94
  homepage: https://light-services-docs.vercel.app/
@@ -79,7 +107,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
79
107
  requirements:
80
108
  - - ">="
81
109
  - !ruby/object:Gem::Version
82
- version: 2.7.0
110
+ version: 3.0.0
83
111
  required_rubygems_version: !ruby/object:Gem::Requirement
84
112
  requirements:
85
113
  - - ">="
@@ -88,5 +116,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
116
  requirements: []
89
117
  rubygems_version: 3.6.9
90
118
  specification_version: 4
91
- summary: Robust service architecture for Ruby frameworks
119
+ summary: Robust service architecture for Ruby/Rails applications
92
120
  test_files: []
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Create class based collections for storing arguments settings, steps settings and outputs settings
4
- #
5
- # General functionality:
6
- # 1. Collection automatically loads data from parent classes
7
- # 2. It's possible to redefine items if needed (e.g. arguments)
8
- # 3. We can add items into collection after or before another items
9
- #
10
- module Light
11
- module Services
12
- module ClassBasedCollection
13
- class Base
14
- # TODO: Add `prepend: true`
15
- def initialize(item_class, allow_redefine)
16
- @item_class = item_class
17
- @allow_redefine = allow_redefine
18
- @collection = {}
19
- end
20
-
21
- def add(klass, name, opts = {})
22
- @collection[klass] ||= all_from_superclass(klass)
23
-
24
- validate_name!(klass, name)
25
- validate_opts!(klass, name, opts)
26
-
27
- item = @item_class.new(name, klass, opts)
28
-
29
- if opts[:before] || opts[:after]
30
- insert_item(klass, name, opts, item)
31
- else
32
- @collection[klass][name] = item
33
- end
34
- end
35
-
36
- def find_index(klass, name)
37
- index = @collection[klass].keys.index(name)
38
-
39
- return index if index
40
-
41
- # TODO: Update `NoStepError` because it maybe not only step
42
- raise Light::Services::NoStepError, "Cannot find #{@item_class} `#{name}` in service #{klass}"
43
- end
44
-
45
- def remove(klass, name)
46
- @collection[klass] ||= all_from_superclass(klass)
47
- @collection[klass].delete(name)
48
- end
49
-
50
- def all(klass)
51
- @collection[klass] || all_from_superclass(klass)
52
- end
53
-
54
- private
55
-
56
- def all_from_superclass(klass)
57
- if klass.superclass <= Light::Services::Base
58
- all(klass.superclass).dup
59
- else
60
- {}
61
- end
62
- end
63
-
64
- def validate_name!(klass, name)
65
- if !@allow_redefine && all(klass).key?(name)
66
- raise Light::Services::Error, "#{@item_class} with name `#{name}` already exists in service #{klass}"
67
- end
68
- end
69
-
70
- def validate_opts!(klass, name, opts)
71
- if opts[:before] && opts[:after]
72
- raise Light::Services::Error, "You cannot specify `before` and `after` " \
73
- "for #{@item_class} `#{name}` in service #{klass} at the same time"
74
- end
75
- end
76
-
77
- def insert_item(klass, name, opts, item)
78
- index = find_index(klass, opts[:before] || opts[:after])
79
- index += 1 unless opts[:before]
80
-
81
- @collection[klass] = @collection[klass].to_a.insert(index, [name, item]).to_h
82
- end
83
- end
84
- end
85
- end
86
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This class allows to mount class based collections to service objects
4
- #
5
- # Usage:
6
- #
7
- # mount_class_based_collection :steps, klass: Settings::Step, shortcut: :step
8
- # mount_class_based_collection :outputs, klass: Settings::Output, shortcut: :output
9
- # mount_class_based_collection :arguments, klass: Settings::Argument, shortcut: :arg, allow_redefine: true
10
- #
11
- module Light
12
- module Services
13
- module ClassBasedCollection
14
- module Mount
15
- def mount_class_based_collection(collection_name, item_class:, shortcut:, allow_redefine: false)
16
- class_variable_set(:"@@#{collection_name}", ClassBasedCollection::Base.new(item_class, allow_redefine))
17
-
18
- define_singleton_method shortcut do |item_name, opts = {}|
19
- class_variable_get(:"@@#{collection_name}").add(self, item_name, opts)
20
- end
21
-
22
- define_singleton_method :"remove_#{shortcut}" do |item_name|
23
- class_variable_get(:"@@#{collection_name}").remove(self, item_name)
24
- end
25
-
26
- define_singleton_method collection_name do
27
- class_variable_get(:"@@#{collection_name}").all(self)
28
- end
29
- end
30
- end
31
- end
32
- end
33
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Collection to store, merge and validate arguments
4
- module Light
5
- module Services
6
- module Collection
7
- class Arguments < Base
8
- def extend_with_context(args)
9
- settings_collection.each do |name, settings|
10
- next if !settings.context || args.key?(name) || !key?(name)
11
-
12
- args[settings.name] = get(name)
13
- end
14
-
15
- args
16
- end
17
-
18
- def validate!
19
- settings_collection.each do |name, settings|
20
- next if settings.optional && (!key?(name) || get(name).nil?)
21
-
22
- settings.validate_type!(get(name))
23
- end
24
- end
25
-
26
- private
27
-
28
- def settings_collection
29
- @instance.class.arguments
30
- end
31
- end
32
- end
33
- end
34
- end
@@ -1,59 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Collection to store arguments and outputs values
4
- module Light
5
- module Services
6
- module Collection
7
- class Base
8
- # Includes
9
- extend Forwardable
10
-
11
- # Settings
12
- def_delegators :@storage, :key?, :to_h
13
-
14
- def initialize(instance, storage = {})
15
- @instance = instance
16
- @storage = storage
17
-
18
- return if storage.is_a?(Hash)
19
-
20
- raise Light::Services::ArgTypeError, "#{instance.class} - arguments must be a Hash"
21
- end
22
-
23
- def set(key, value)
24
- @storage[key] = value
25
- end
26
-
27
- def get(key)
28
- @storage[key]
29
- end
30
-
31
- def [](key)
32
- get(key)
33
- end
34
-
35
- def []=(key, value)
36
- set(key, value)
37
- end
38
-
39
- def load_defaults
40
- settings_collection.each do |name, settings|
41
- next if !settings.default_exists || key?(name)
42
-
43
- if settings.default.is_a?(Proc)
44
- set(name, @instance.instance_exec(&settings.default))
45
- else
46
- set(name, deep_dup(settings.default))
47
- end
48
- end
49
- end
50
-
51
- private
52
-
53
- def deep_dup(object)
54
- Marshal.load(Marshal.dump(object))
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Collection to store outputs values
4
- module Light
5
- module Services
6
- module Collection
7
- class Outputs < Base
8
- private
9
-
10
- def settings_collection
11
- @instance.class.outputs
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This class defines settings for argument
4
- module Light
5
- module Services
6
- module Settings
7
- class Argument
8
- # Getters
9
- attr_reader :name, :default_exists, :default, :context, :optional, :arg_types_cache
10
-
11
- def initialize(name, service_class, opts = {})
12
- @name = name
13
- @service_class = service_class
14
-
15
- @type = opts.delete(:type)
16
- @context = opts.delete(:context)
17
- @default_exists = opts.key?(:default)
18
- @default = opts.delete(:default)
19
- @optional = opts.delete(:optional)
20
-
21
- @arg_types_cache = {}
22
-
23
- define_methods
24
- end
25
-
26
- def validate_type!(value)
27
- return if !@type || [*@type].any? do |type|
28
- case type
29
- when :boolean
30
- value.is_a?(TrueClass) || value.is_a?(FalseClass)
31
- when Symbol
32
- arg_type(value) == type
33
- else
34
- value.is_a?(type)
35
- end
36
- end
37
-
38
- raise Light::Services::ArgTypeError, "#{@service_class} argument `#{name}` must be " \
39
- "a #{[*@type].join(', ')} (currently: #{value.class})"
40
- end
41
-
42
- private
43
-
44
- def arg_type(value)
45
- klass = value.class
46
-
47
- @arg_types_cache[klass] ||= klass
48
- .name
49
- .gsub("::", "/")
50
- .gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
51
- .gsub(/([a-z\d])([A-Z])/, '\1_\2')
52
- .tr("-", "_")
53
- .downcase
54
- .to_sym
55
- end
56
-
57
- def define_methods
58
- name = @name
59
-
60
- @service_class.define_method(@name) { @arguments.get(name) }
61
- @service_class.define_method(:"#{@name}?") { !!@arguments.get(name) }
62
- @service_class.define_method(:"#{@name}=") { |value| @arguments.set(name, value) }
63
- @service_class.send(:private, "#{@name}=")
64
- end
65
- end
66
- end
67
- end
68
- end