substance 0.26.0.2

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: db4e95d7f330b7ac29bdd857017b427defc87f0ad9796fec42bc63efa3cdb485
4
+ data.tar.gz: 14b97d6b1687f5620836a7937af9046af9969149bfffc7741fb4c944e411d348
5
+ SHA512:
6
+ metadata.gz: 597f3c854d96eba40a7edea903137bf395b95c1dd1e76e58965251c1e0ca58e9e86da8e2ef0885ac4b3d7f782a7c78dd1a1cb6e18e2f1900d0dfbc51d6879322
7
+ data.tar.gz: f206aa732c3e7d3f10b5bfd0b726be2f812a8c82a2c1294dd318fc27311fd097dea82a021c10446656a5fe9c8b03ef98c9600d010a5f075719a75c258cce68a3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Allen Rettberg
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # Substance
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/substance`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'substance'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install substance
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/substance.
36
+
37
+
38
+ ## License
39
+
40
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/lib/substance.rb ADDED
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "substance/version"
4
+
5
+ require_relative "substance/root_object"
6
+ require_relative "substance/attribute_object"
7
+ require_relative "substance/input_object"
8
+ require_relative "substance/input_model"
9
+ require_relative "substance/output_object"
10
+
11
+ module Substance
12
+ class Error < StandardError; end
13
+ class NotValidatedError < Error; end
14
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "root_object"
4
+ require_relative "objects/defaults"
5
+ require_relative "objects/attributes"
6
+
7
+ module Substance
8
+ class AttributeObject < Substance::RootObject
9
+ include Substance::Objects::Defaults
10
+ include Substance::Objects::Attributes
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "input_object"
4
+
5
+ module Substance
6
+ class InputModel < InputObject
7
+ extend ActiveModel::Naming
8
+ extend ActiveModel::Translation
9
+
10
+ include ActiveModel::Conversion
11
+ include ActiveModel::Validations
12
+ include ActiveModel::Validations::Callbacks
13
+ end
14
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "attribute_object"
4
+ require_relative "objects/arguments"
5
+ require_relative "objects/options"
6
+
7
+ module Substance
8
+ class InputObject < Substance::AttributeObject
9
+ define_callbacks :initialize
10
+
11
+ include Substance::Objects::Arguments
12
+ include Substance::Objects::Options
13
+
14
+ def initialize(**input)
15
+ @input = input
16
+ run_callbacks(:initialize) do
17
+ input.each { |key, value| __send__("#{key}=".to_sym, value) }
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :input
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Arguments describe input that is required (which can be nil, unless otherwise specified).
4
+ module Substance
5
+ module Objects
6
+ module Arguments
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :_arguments, instance_writer: false, default: {}
11
+ set_callback :initialize, :after do
12
+ missing_arguments = _arguments.reject do |argument, options|
13
+ options[:allow_nil] ? input.key?(argument) : !input[argument].nil?
14
+ end
15
+
16
+ missing = missing_arguments.keys
17
+
18
+ raise ArgumentError, "Missing #{"argument".pluralize(missing.length)}: #{missing.join(", ")}" if missing.any?
19
+ end
20
+ end
21
+
22
+ class_methods do
23
+ def inherited(base)
24
+ dup = _arguments.dup
25
+ base._arguments = dup.each { |k, v| dup[k] = v.dup }
26
+ super
27
+ end
28
+
29
+ private
30
+
31
+ def argument(argument, allow_nil: true)
32
+ _arguments[argument] = { allow_nil: allow_nil }
33
+ define_attribute argument
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Attributes are structured data within an object.
4
+ module Substance
5
+ module Objects
6
+ module Attributes
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :_attributes, instance_writer: false, default: []
11
+ end
12
+
13
+ class_methods do
14
+ def inherited(base)
15
+ base._attributes = _attributes.dup
16
+ super
17
+ end
18
+
19
+ private
20
+
21
+ def define_attribute(attribute)
22
+ _attributes << attribute
23
+ attr_accessor attribute
24
+ end
25
+ alias_method :attribute, :define_attribute
26
+ end
27
+
28
+ def to_h
29
+ _attributes.each_with_object({}) { |attr, hash| hash[attr] = public_send(attr) }
30
+ end
31
+
32
+ private
33
+
34
+ def stringable_attributes
35
+ self.class._attributes
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tablesalt/isolation"
4
+
5
+ # Defaults are used as the value when then attribute is unspecified.
6
+ module Substance
7
+ module Objects
8
+ module Defaults
9
+ extend ActiveSupport::Concern
10
+
11
+ included do
12
+ class_attribute :_defaults, instance_writer: false, default: {}
13
+ end
14
+
15
+ class_methods do
16
+ def inherited(base)
17
+ dup = _defaults.dup
18
+ base._defaults = dup.each { |k, v| dup[k] = v.dup }
19
+ super
20
+ end
21
+
22
+ private
23
+
24
+ def define_default(attribute, static: nil, &block)
25
+ _defaults[attribute] = Value.new(static: static, &block)
26
+ end
27
+ end
28
+
29
+ class Value
30
+ include Tablesalt::Isolation
31
+
32
+ def initialize(static: nil, &block)
33
+ @value = (static.nil? && block_given?) ? block : static
34
+ end
35
+
36
+ def value
37
+ isolate(@value.respond_to?(:call) ? instance_eval(&@value) : @value)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Options describe input which may be provided to define or override default values.
4
+ module Substance
5
+ module Objects
6
+ module Options
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ class_attribute :_options, instance_writer: false, default: []
11
+
12
+ set_callback :initialize, :after do
13
+ _options.each do |option|
14
+ next unless _defaults.key?(option)
15
+
16
+ public_send("#{option}=".to_sym, _defaults[option].value) if public_send(option).nil?
17
+ end
18
+ end
19
+ end
20
+
21
+ class_methods do
22
+ def inherited(base)
23
+ base._options = _options.dup
24
+ super
25
+ end
26
+
27
+ private
28
+
29
+ def option(option, default: nil, &block)
30
+ _options << option
31
+ define_attribute option
32
+ define_default option, static: default, &block
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Substance
4
+ module Objects
5
+ module Output
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include AroundTheWorld
10
+
11
+ class_attribute :_outputs, instance_writer: false, default: []
12
+
13
+ delegate :_outputs, to: :class
14
+
15
+ after_validation do
16
+ next unless validated?
17
+
18
+ _outputs.each do |key|
19
+ public_send("#{key}=".to_sym, _defaults[key].value) if _defaults.key?(key) && public_send(key).nil?
20
+ end
21
+ end
22
+ end
23
+
24
+ class_methods do
25
+ def inherited(base)
26
+ base._outputs = _outputs.dup
27
+ super
28
+ end
29
+
30
+ private
31
+
32
+ def output(output, default: nil, &block)
33
+ _outputs << output
34
+ define_attribute output
35
+ define_default output, static: default, &block
36
+ ensure_validation_before output
37
+ ensure_validation_before "#{output}=".to_sym
38
+ end
39
+
40
+ def ensure_validation_before(method)
41
+ around_method method do |*args, **opts|
42
+ raise NotValidatedError unless validated?
43
+
44
+ # TODO: replace with `super(...)` when <= 2.6 support is dropped
45
+ if RUBY_VERSION < "2.7" && opts.blank?
46
+ super(*args)
47
+ else
48
+ super(*args, **opts)
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def outputs
55
+ return {} if _outputs.empty?
56
+
57
+ output_struct.new(*_outputs.map(&method(:public_send)))
58
+ end
59
+
60
+ def output_struct
61
+ Struct.new(*_outputs)
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Substance
4
+ module Objects
5
+ module Status
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ after_validation { self.was_validated = errors.empty? }
10
+
11
+ private
12
+
13
+ attr_accessor :was_validated
14
+ end
15
+
16
+ def validated?
17
+ was_validated.present?
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "input_model"
4
+ require_relative "objects/status"
5
+ require_relative "objects/output"
6
+
7
+ module Substance
8
+ class OutputObject < InputModel
9
+ include Objects::Status
10
+ include Objects::Output
11
+ end
12
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/callbacks"
4
+ require "short_circu_it"
5
+ require "technologic"
6
+ require "tablesalt/stringable_object"
7
+
8
+ module Substance
9
+ class RootObject
10
+ include ActiveSupport::Callbacks
11
+ include ShortCircuIt
12
+ include Technologic
13
+ include Tablesalt::StringableObject
14
+
15
+ class << self
16
+ private
17
+
18
+ def define_callbacks_with_handler(*events, handler: :on, filter: :after)
19
+ define_callbacks(*events)
20
+
21
+ events.each do |event|
22
+ define_singleton_method("#{handler}_#{event}".to_sym) do |*filters, &block|
23
+ set_callback(event, filter, *filters, &block)
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "rspec/custom_matchers"
4
+ require_relative "rspec/shared_examples"
5
+ require_relative "rspec/shoulda_matcher_helper"
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "custom_matchers/define_argument"
4
+ require_relative "custom_matchers/define_attribute"
5
+ require_relative "custom_matchers/define_option"
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests usage of `.argument`
4
+ #
5
+ # class Example < Substance::InputObject
6
+ # argument :foo
7
+ # argument :bar, allow_nil: false
8
+ # end
9
+ #
10
+ # RSpec.describe Example, type: :input_object do
11
+ # subject { described_class.new(**input) }
12
+ #
13
+ # let(:input) { {} }
14
+ #
15
+ # it { is_expected.to define_argument :foo }
16
+ # it { is_expected.to define_argument :bar, allow_nil: false }
17
+ # end
18
+
19
+ RSpec::Matchers.define :define_argument do |argument, allow_nil: true|
20
+ match { |instance| expect(instance._arguments[argument]).to eq(allow_nil: allow_nil) }
21
+ description { "define argument #{argument}" }
22
+ failure_message do
23
+ "expected #{described_class} to define argument #{argument} #{prohibit_nil_description unless allow_nil}"
24
+ end
25
+
26
+ def prohibit_nil_description
27
+ "and prohibit a nil value"
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests usage of `.attribute`
4
+ #
5
+ # class Example < Substance::InputObject
6
+ # attribute :foo
7
+ # end
8
+ #
9
+ # RSpec.describe Example, type: :input_object do
10
+ # subject { described_class.new(**input) }
11
+ #
12
+ # let(:input) { {} }
13
+ #
14
+ # it { is_expected.to define_attribute :foo }
15
+ # end
16
+
17
+ RSpec::Matchers.define :define_attribute do |attribute|
18
+ match { |instance| expect(instance._attributes).to include attribute }
19
+ description { "define attribute #{attribute}" }
20
+ failure_message { "expected #{described_class} to defines attribute #{attribute}" }
21
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ # RSpec matcher that tests usage of `.option`
4
+ #
5
+ # class Example < Substance::InputObject
6
+ # option :foo
7
+ # option :bar, default: :baz
8
+ # option(:gaz) { :haz }
9
+ # end
10
+ #
11
+ # RSpec.describe Example, type: :input_object do
12
+ # subject { described_class.new(**input) }
13
+ #
14
+ # let(:input) { {} }
15
+ #
16
+ # it { is_expected.to define_option :foo }
17
+ # it { is_expected.to define_option :bar, default: :baz }
18
+ # it { is_expected.to define_option :gaz, default: :haz }
19
+ # end
20
+
21
+ RSpec::Matchers.define :define_option do |option, default: nil|
22
+ match do |instance|
23
+ expect(instance._defaults[option]&.value).to eq default
24
+ expect(instance._options).to include option
25
+ end
26
+ description { "define option #{option}" }
27
+ failure_message { "expected #{described_class} to define option #{option} #{for_default(default)}" }
28
+
29
+ def for_default(default)
30
+ return "without a default value" if default.nil?
31
+
32
+ "with default value #{default}"
33
+ end
34
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "shared_examples/an_input_object_with_a_class_collection_attribute"
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.shared_examples_for "an input object with a class collection attribute" do |method, collection|
4
+ subject(:define) { example_input_object_class.__send__(method, value) }
5
+
6
+ let(:value) { Faker::Lorem.word.to_sym }
7
+
8
+ before do
9
+ allow(example_input_object_class).to receive(:define_default).and_call_original
10
+ allow(example_input_object_class).to receive(:define_attribute).and_call_original
11
+ end
12
+
13
+ describe "defines value" do
14
+ let(:default) { Faker::Lorem.word }
15
+
16
+ shared_examples_for "an value is defined" do
17
+ it "adds to _values" do
18
+ expect { define }.to change { example_input_object_class.public_send(collection) }.from([]).to([ value ])
19
+ end
20
+ end
21
+
22
+ context "when no block is given" do
23
+ subject(:define) { example_input_object_class.__send__(method, value, default: default) }
24
+
25
+ it_behaves_like "an value is defined"
26
+
27
+ it "defines an static default" do
28
+ define
29
+ expect(example_input_object_class).to have_received(:define_default).with(value, static: default)
30
+ end
31
+ end
32
+
33
+ context "when a block is given" do
34
+ subject(:define) { example_input_object_class.__send__(method, value, default: default, &block) }
35
+
36
+ let(:block) do
37
+ ->(_) { :block }
38
+ end
39
+
40
+ shared_examples_for "values are handed off to define_default" do
41
+ it "calls define_default" do
42
+ define
43
+ expect(example_input_object_class).to have_received(:define_default).with(value, static: default, &block)
44
+ end
45
+ end
46
+
47
+ context "with a static default" do
48
+ it_behaves_like "values are handed off to define_default"
49
+ end
50
+
51
+ context "without a static default" do
52
+ let(:default) { nil }
53
+
54
+ it_behaves_like "values are handed off to define_default"
55
+ end
56
+ end
57
+ end
58
+
59
+ it "defines an attribute" do
60
+ define
61
+ expect(example_input_object_class).to have_received(:define_attribute).with(value)
62
+ end
63
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Shoulda::Matchers::ActiveModel)
4
+ RSpec.configure do |config|
5
+ config.include(Shoulda::Matchers::ActiveModel, type: :input_object)
6
+ config.include(Shoulda::Matchers::ActiveModel, type: :input_model)
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Substance
4
+ # This constant is managed by spicerack
5
+ VERSION = "0.26.0.2"
6
+ end
metadata ADDED
@@ -0,0 +1,229 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: substance
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.26.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Freshly Engineering
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-04-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.2.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: short_circu_it
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.26.0.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.26.0.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: tablesalt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.26.0.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.26.0.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: technologic
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.26.0.2
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 0.26.0.2
69
+ - !ruby/object:Gem::Dependency
70
+ name: faker
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '1.8'
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '2.0'
79
+ type: :development
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '1.8'
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '2.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: '3.0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: bundler
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 2.0.1
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: 2.0.1
117
+ - !ruby/object:Gem::Dependency
118
+ name: pry
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - "~>"
122
+ - !ruby/object:Gem::Version
123
+ version: 0.10.0
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - "~>"
129
+ - !ruby/object:Gem::Version
130
+ version: 0.10.0
131
+ - !ruby/object:Gem::Dependency
132
+ name: pry-nav
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: 0.2.4
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: 0.2.4
145
+ - !ruby/object:Gem::Dependency
146
+ name: rake
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: 12.3.3
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: 12.3.3
159
+ - !ruby/object:Gem::Dependency
160
+ name: shoulda-matchers
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - '='
164
+ - !ruby/object:Gem::Version
165
+ version: 4.0.1
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - '='
171
+ - !ruby/object:Gem::Version
172
+ version: 4.0.1
173
+ description: Base classes for building powerful service objects
174
+ email:
175
+ - eng@freshly.com
176
+ executables: []
177
+ extensions: []
178
+ extra_rdoc_files: []
179
+ files:
180
+ - LICENSE.txt
181
+ - README.md
182
+ - lib/substance.rb
183
+ - lib/substance/attribute_object.rb
184
+ - lib/substance/input_model.rb
185
+ - lib/substance/input_object.rb
186
+ - lib/substance/objects/arguments.rb
187
+ - lib/substance/objects/attributes.rb
188
+ - lib/substance/objects/defaults.rb
189
+ - lib/substance/objects/options.rb
190
+ - lib/substance/objects/output.rb
191
+ - lib/substance/objects/status.rb
192
+ - lib/substance/output_object.rb
193
+ - lib/substance/root_object.rb
194
+ - lib/substance/rspec.rb
195
+ - lib/substance/rspec/custom_matchers.rb
196
+ - lib/substance/rspec/custom_matchers/define_argument.rb
197
+ - lib/substance/rspec/custom_matchers/define_attribute.rb
198
+ - lib/substance/rspec/custom_matchers/define_option.rb
199
+ - lib/substance/rspec/shared_examples.rb
200
+ - lib/substance/rspec/shared_examples/an_input_object_with_a_class_collection_attribute.rb
201
+ - lib/substance/rspec/shoulda_matcher_helper.rb
202
+ - lib/substance/version.rb
203
+ homepage: https://github.com/Freshly/spicerack/blob/main/substance
204
+ licenses:
205
+ - MIT
206
+ metadata:
207
+ homepage_uri: https://github.com/Freshly/spicerack/blob/main/substance
208
+ source_code_uri: https://github.com/Freshly/spicerack/blob/main/substance
209
+ changelog_uri: https://github.com/Freshly/spicerack/blob/main/substance/CHANGELOG.md
210
+ post_install_message:
211
+ rdoc_options: []
212
+ require_paths:
213
+ - lib
214
+ required_ruby_version: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ version: 2.5.0
219
+ required_rubygems_version: !ruby/object:Gem::Requirement
220
+ requirements:
221
+ - - ">="
222
+ - !ruby/object:Gem::Version
223
+ version: '0'
224
+ requirements: []
225
+ rubygems_version: 3.1.6
226
+ signing_key:
227
+ specification_version: 4
228
+ summary: Base classes for building powerful service objects
229
+ test_files: []