range_component_attributes 1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8620dd0c7969d1c9e208cda4752a2a1fa4cdb50df9d7682893bbcbff1e5f33fe
4
+ data.tar.gz: de34c8c1ab186210b728e9c38d4f1f3c2fe53731f578f2799a1aa607b664fd04
5
+ SHA512:
6
+ metadata.gz: 6f46ce5122733699261f698af2a40275ab6f4774dbc95aa72676073a604f3fbb97d54ccd6a3166e2ddad9e5c4d2f73f1558063d5f7c71a84fc117143deb9a162
7
+ data.tar.gz: e0e13edf7e6e434acef25d2ca50b6ff5a6846a7c835fe3e7887e7d79598209e6c78da1ffb258c9be5ec9365e7fce7758218d87db73368a03f2a6884715215bef
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.5.1
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.5.1
5
+
6
+ addons:
7
+ postgresql: "9.6"
8
+
9
+ before_install: gem install bundler -v 1.16.1
10
+
11
+ before_script:
12
+ - cp spec/database.yml.travis spec/database.yml
13
+ - bundle exec rake db:setup
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in range_component_attributes.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,59 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ range_component_attributes (1.0.0)
5
+ activerecord (>= 5.2.0)
6
+ activesupport (>= 5.2.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ activemodel (5.2.0)
12
+ activesupport (= 5.2.0)
13
+ activerecord (5.2.0)
14
+ activemodel (= 5.2.0)
15
+ activesupport (= 5.2.0)
16
+ arel (>= 9.0)
17
+ activesupport (5.2.0)
18
+ concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ i18n (>= 0.7, < 2)
20
+ minitest (~> 5.1)
21
+ tzinfo (~> 1.1)
22
+ ansi (1.5.0)
23
+ arel (9.0.0)
24
+ builder (3.2.3)
25
+ coderay (1.1.2)
26
+ concurrent-ruby (1.0.5)
27
+ i18n (1.0.1)
28
+ concurrent-ruby (~> 1.0)
29
+ method_source (0.9.0)
30
+ minitest (5.11.3)
31
+ minitest-reporters (1.2.0)
32
+ ansi
33
+ builder
34
+ minitest (>= 5.0)
35
+ ruby-progressbar
36
+ pg (1.0.0)
37
+ pry (0.11.3)
38
+ coderay (~> 1.1.0)
39
+ method_source (~> 0.9.0)
40
+ rake (10.5.0)
41
+ ruby-progressbar (1.9.0)
42
+ thread_safe (0.3.6)
43
+ tzinfo (1.2.5)
44
+ thread_safe (~> 0.1)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ bundler (~> 1.16)
51
+ minitest (~> 5.0)
52
+ minitest-reporters
53
+ pg (~> 1.0)
54
+ pry
55
+ rake (~> 10.0)
56
+ range_component_attributes!
57
+
58
+ BUNDLED WITH
59
+ 1.16.1
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 CCSalesPro
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,102 @@
1
+ # Range Component Attributes
2
+
3
+ This gem creates attributes for the lower and upper bounds of a range on an
4
+ ActiveRecord object. These attributes are automatically populated when a record
5
+ is loaded and they are written to the underlying range when a record is saved.
6
+ This makes it easier to work with ActiveRecord validations and form helpers.
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem 'range_component_attributes'
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install range_component_attributes
23
+
24
+ ## Usage
25
+
26
+ Include `RangeComponentAttributes` module in classes you want to work with range
27
+ components. You can include it in `ActiveRecord::Base` or `ApplicationRecord` if
28
+ you want it available in all models.
29
+
30
+ Use class method `range_component_attributes` to create range component attributes.
31
+
32
+ ```ruby
33
+ class Widget < ActiveRecord::Base
34
+ include RangeComponentAttributes
35
+
36
+ range_component_attributes :valid_dates,
37
+ lower_name: :valid_from,
38
+ upper_name: :valid_to,
39
+ type_converter: DateConverter.new,
40
+ crossed_bounds_message: "must be less than valid to"
41
+
42
+ range_component_attributes :valid_prices,
43
+ lower_name: :min_price,
44
+ upper_name: :max_price,
45
+ lower_type_converter: DecimalConverter.new,
46
+ upper_type_converter: DecimalConverter.new(blank_value: Float::INFINITY)
47
+ end
48
+
49
+ widget = Widget.new min_price: "10", max_price: "20"
50
+ widget.valid_prices #=> 0.1e2...0.2e2
51
+ ```
52
+
53
+ range_component_attributes creates attributes corresponding to the lower and
54
+ upper bounds of `range_name`. `lower_name` and `upper_name` controls the names
55
+ of these attributes.
56
+
57
+ `type_converter` is a callable object that converts its argument to the proper
58
+ type. There are builtin type converters `IntegerConverter`, `DecimalConverter`,
59
+ `FloatConverter`, and `DateConverter`.
60
+
61
+ In addition, `lower_type_converter` and `upper_type_converter` can be separately
62
+ specified. This is especially useful when the attributeould behave differently
63
+ for blank values. For example, the upper bound mant to consider a blank value as
64
+ Float::INFINITY.
65
+
66
+ `exclude_end` controls whether the end is exclusive or not. Ranges are
67
+ automatically normalized to this type. This is useful because PostgreSQL
68
+ automatically normalizes ranges of discrete values to exclusive endsg. `[1, 10]`
69
+ becomes `[1,11)`. RangeComponentAttributes will handle this so the exact bound
70
+ values persist even when PostgreSQL has changed them.
71
+
72
+ Validations are automatically added that create an error if an assignment to
73
+ bounds attribute fails due to a type conversion error. In addition, a validation
74
+ checks that the lower bound is less than the upper bound. This error message can
75
+ be customized by supplying `crossed_bounds_message`.
76
+
77
+ ## Development
78
+
79
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run
80
+ `rake test` to run the tests. You can also run `bin/console` for an interactive
81
+ prompt that will allow you to experiment.
82
+
83
+ To install this gem onto your local machine, run `bundle exec rake install`. To
84
+ release a new version, update the version number in `version.rb`, and then run
85
+ `bundle exec rake release`, which will create a git tag for the version, push
86
+ git commits and tags, and push the `.gem` file to
87
+ [rubygems.org](https://rubygems.org).
88
+
89
+ To run the tests, first run `rake db:setup`. This creates a database called
90
+ `range_component_attributes_test` and load `database_structure.sql` into it.
91
+ Then run `rake`.
92
+
93
+
94
+ ## Contributing
95
+
96
+ Bug reports and pull requests are welcome on GitHub at
97
+ https://github.com/ccsalespro/range_component_attributes.
98
+
99
+ ## License
100
+
101
+ The gem is available as open source under the terms of the [MIT
102
+ License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ namespace :db do
5
+ desc 'bootstrap database'
6
+ task :setup do
7
+ sh "createdb range_component_attributes_test || true"
8
+ sh "psql -f test/database_structure.sql range_component_attributes_test"
9
+ end
10
+ end
11
+
12
+ Rake::TestTask.new(:test) do |t|
13
+ t.libs << "test"
14
+ t.libs << "lib"
15
+ t.test_files = FileList["test/**/*_test.rb"]
16
+ end
17
+
18
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "range_component_attributes"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,108 @@
1
+ require "range_component_attributes/range_wrapper"
2
+ require "range_component_attributes/type_conversion"
3
+ require "range_component_attributes/version"
4
+
5
+ require "active_support"
6
+
7
+ module RangeComponentAttributes
8
+ extend ActiveSupport::Concern
9
+
10
+ class_methods do
11
+ # range_component_attributes creates attributes corresponding to the lower
12
+ # and upper bounds of `range_name`. `lower_name` and `upper_name` controls
13
+ # the names of these attributes.
14
+ #
15
+ # `type_converter` is a callable object that converts its argument to the
16
+ # proper type. There are builtin type converters `IntegerConverter`,
17
+ # `DecimalConverter`, `FloatConverter`, and `DateConverter`.
18
+ #
19
+ # In addition, `lower_type_converter` and `upper_type_converter` can be
20
+ # separately specified. This is especially useful when the attributes should
21
+ # behave differently for blank values. For example, the upper bound may want
22
+ # to consider a blank value as Float::INFINITY.
23
+ #
24
+ # `exclude_end` controls whether the end is exclusive or not. Ranges are
25
+ # automatically normalized to this type. This is useful because PostgreSQL
26
+ # automatically normalizes ranges of discrete values to exclusive ends. e.g.
27
+ # `[1, 10]` becomes `[1,11)`. RangeComponentAttributes will handle this so
28
+ # the exact bound values persist even when PostgreSQL has changed them.
29
+ #
30
+ # Validations are automatically added that create an error if an assignment
31
+ # to bounds attribute fails due to a type conversion error. In addition, a
32
+ # validation checks that the lower bound is less than the upper bound. This
33
+ # error message can be customized by supplying `crossed_bounds_message`.
34
+ def range_component_attributes(
35
+ range_name,
36
+ lower_name: "#{range_name}_lower",
37
+ upper_name: "#{range_name}_upper",
38
+ type_converter: nil,
39
+ lower_type_converter: nil,
40
+ upper_type_converter: nil,
41
+ exclude_end: true,
42
+ crossed_bounds_message: "must be less than upper bound"
43
+ )
44
+ range_wrapper_name = "#{range_name}_wrapper"
45
+ lower_type_converter ||= type_converter
46
+ upper_type_converter ||= type_converter
47
+ raise ArgumentError, "must provide lower_type_converter or type_converter" unless lower_type_converter
48
+ raise ArgumentError, "must provide upper_type_converter or type_converter" unless upper_type_converter
49
+
50
+ mod = Module.new do
51
+ define_method range_wrapper_name do
52
+ instance_variable_get("@#{range_wrapper_name}") ||
53
+ instance_variable_set("@#{range_wrapper_name}",
54
+ RangeWrapper.new(
55
+ lower_type_converter: lower_type_converter,
56
+ upper_type_converter: upper_type_converter,
57
+ exclude_end: exclude_end,
58
+ range: send(range_name),
59
+ crossed_bounds_message: crossed_bounds_message
60
+ )
61
+ )
62
+ end
63
+
64
+ define_method "#{lower_name}" do
65
+ send(range_wrapper_name).lower
66
+ end
67
+
68
+ define_method "#{lower_name}=" do |val|
69
+ range_wrapper = send(range_wrapper_name)
70
+ range_wrapper.lower = val
71
+ if range_wrapper.valid?
72
+ send("#{range_name}=", range_wrapper.range)
73
+ end
74
+ end
75
+
76
+ define_method "#{upper_name}" do
77
+ send(range_wrapper_name).upper
78
+ end
79
+
80
+ define_method "#{upper_name}=" do |val|
81
+ range_wrapper = send(range_wrapper_name)
82
+ range_wrapper.upper = val
83
+ if range_wrapper.valid?
84
+ send("#{range_name}=", range_wrapper.range)
85
+ end
86
+ end
87
+
88
+ define_method "#{range_name}=" do |val|
89
+ send(range_wrapper_name).range = val
90
+ super val
91
+ end
92
+
93
+ define_method "check_#{range_name}_errors" do
94
+ range_wrapper = send(range_wrapper_name)
95
+ unless range_wrapper.valid?
96
+ errors.add lower_name, range_wrapper.errors[:lower] if range_wrapper.errors[:lower]
97
+ errors.add upper_name, range_wrapper.errors[:upper] if range_wrapper.errors[:upper]
98
+ errors.add upper_name, range_wrapper.errors[:range] if range_wrapper.errors[:range]
99
+ end
100
+ end
101
+ end
102
+
103
+ validate "check_#{range_name}_errors".to_sym
104
+
105
+ self.include mod
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,105 @@
1
+ module RangeComponentAttributes
2
+ class InvalidRangeError < StandardError; end
3
+
4
+ class RangeWrapper
5
+ attr_reader :errors
6
+
7
+ def initialize(
8
+ # Range type
9
+ lower_type_converter:,
10
+ upper_type_converter:,
11
+ exclude_end: true,
12
+
13
+ # Initial values
14
+ lower: nil,
15
+ upper: nil,
16
+ range: nil,
17
+
18
+ crossed_bounds_message: "must be less than upper bound"
19
+ )
20
+ raise ArgumentError, "lower/upper and range are mutually exclusive" if (lower || upper) && range
21
+
22
+ @errors = {}
23
+ @lower_type_converter = lower_type_converter
24
+ @upper_type_converter = upper_type_converter
25
+ @exclude_end = exclude_end
26
+ @crossed_bounds_message = crossed_bounds_message
27
+
28
+ if range
29
+ self.range = range
30
+ else
31
+ self.lower = lower
32
+ self.upper = upper
33
+ end
34
+ end
35
+
36
+ def range
37
+ raise InvalidRangeError unless valid?
38
+ @range
39
+ end
40
+
41
+ def range=(x)
42
+ if x
43
+ @lower = x.begin
44
+ @upper = x.end
45
+ if x.exclude_end? != @exclude_end && @upper.respond_to?(:next)
46
+ @upper += x.exclude_end? ? -1 : 1
47
+ end
48
+ convert_lower_and_upper_to_range
49
+ else
50
+ @lower = nil
51
+ @upper = nil
52
+ @range = nil
53
+ end
54
+ end
55
+
56
+ def lower
57
+ @lower
58
+ end
59
+
60
+ def lower=(x)
61
+ @lower = begin
62
+ @lower_type_converter.(x).tap { errors.delete(:lower) }
63
+ rescue TypeConversionError => e
64
+ errors[:lower] = "is not a #{e.target_type}"
65
+ x
66
+ end
67
+ convert_lower_and_upper_to_range
68
+ end
69
+
70
+ def upper
71
+ @upper
72
+ end
73
+
74
+ def upper=(x)
75
+ @upper = begin
76
+ @upper_type_converter.(x).tap { errors.delete(:upper) }
77
+ rescue TypeConversionError => e
78
+ errors[:upper] = "is not a #{e.target_type}"
79
+ x
80
+ end
81
+ convert_lower_and_upper_to_range
82
+ end
83
+
84
+ def valid?
85
+ errors.empty?
86
+ end
87
+
88
+ private
89
+
90
+ def convert_lower_and_upper_to_range
91
+ return nil unless errors.keys.reject { |k| k == :range }.empty?
92
+ @range = if @lower != @lower_type_converter.blank_value || @upper != @upper_type_converter.blank_value
93
+ Range.new(@lower, @upper, @exclude_end)
94
+ else
95
+ nil
96
+ end
97
+ errors.clear
98
+
99
+ crossed_bounds = lower > upper rescue nil
100
+ errors[:lower] = @crossed_bounds_message if crossed_bounds
101
+ rescue ArgumentError => e
102
+ errors[:range] = e.to_s
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,64 @@
1
+ module RangeComponentAttributes
2
+ class TypeConversionError < StandardError
3
+ attr_reader :original_error, :target_type
4
+
5
+ def initialize(original_error, target_type)
6
+ @original_error = original_error
7
+ @target_type = target_type
8
+ end
9
+ end
10
+
11
+ class BaseConverter
12
+ attr_reader :blank_value
13
+
14
+ def initialize blank_value: nil
15
+ @blank_value = blank_value
16
+ end
17
+ end
18
+
19
+ class IntegerConverter < BaseConverter
20
+ def call(value)
21
+ return @blank_value if value.blank?
22
+ return value if value == Float::INFINITY
23
+ Integer(value)
24
+ rescue StandardError => e
25
+ raise TypeConversionError.new(e, "integer")
26
+ end
27
+ end
28
+
29
+ class DecimalConverter < BaseConverter
30
+ def call(value)
31
+ return @blank_value if value.blank?
32
+ return value if value == Float::INFINITY
33
+ BigDecimal(value, 16)
34
+ rescue StandardError => e
35
+ raise TypeConversionError.new(e, "number")
36
+ end
37
+ end
38
+
39
+ class FloatConverter < BaseConverter
40
+ def call(value)
41
+ return @blank_value if value.blank?
42
+ return value if value == Float::INFINITY
43
+ Float(value)
44
+ rescue StandardError => e
45
+ raise TypeConversionError.new(e, "number")
46
+ end
47
+ end
48
+
49
+ class DateConverter < BaseConverter
50
+ def call(value)
51
+ return @blank_value if value.blank?
52
+ return value if value == Float::INFINITY
53
+ return value if value.kind_of? Date
54
+ value = value.to_s
55
+ if value =~ /\A(\d\d\d\d)-(\d\d)-(\d\d)\z/
56
+ ::Date.civil($1.to_i, $2.to_i, $3.to_i)
57
+ else
58
+ ::Date.strptime(value, "%m/%d/%Y")
59
+ end
60
+ rescue StandardError => e
61
+ raise TypeConversionError.new(e, "date")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,3 @@
1
+ module RangeComponentAttributes
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,32 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "range_component_attributes/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "range_component_attributes"
8
+ spec.version = RangeComponentAttributes::VERSION
9
+ spec.authors = ["Jack Christensen"]
10
+ spec.email = ["jack@jackchristensen.com"]
11
+
12
+ spec.summary = %q{Splits database ranges into lower and upper attributes in ActiveRecord}
13
+ spec.homepage = "https://github.com/ccsalespro/range_component_attributes"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_dependency 'activerecord', ">= 5.2.0"
24
+ spec.add_dependency 'activesupport', ">= 5.2.0"
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.16"
27
+ spec.add_development_dependency "minitest", "~> 5.0"
28
+ spec.add_development_dependency "minitest-reporters"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency 'pg', "~> 1.0"
31
+ spec.add_development_dependency 'pry'
32
+ end
metadata ADDED
@@ -0,0 +1,171 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: range_component_attributes
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jack Christensen
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activerecord
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.2.0
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.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: activesupport
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 5.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 5.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.16'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.16'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '5.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '5.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pg
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description:
126
+ email:
127
+ - jack@jackchristensen.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".ruby-version"
134
+ - ".travis.yml"
135
+ - Gemfile
136
+ - Gemfile.lock
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - bin/console
141
+ - bin/setup
142
+ - lib/range_component_attributes.rb
143
+ - lib/range_component_attributes/range_wrapper.rb
144
+ - lib/range_component_attributes/type_conversion.rb
145
+ - lib/range_component_attributes/version.rb
146
+ - range_component_attributes.gemspec
147
+ homepage: https://github.com/ccsalespro/range_component_attributes
148
+ licenses:
149
+ - MIT
150
+ metadata: {}
151
+ post_install_message:
152
+ rdoc_options: []
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ requirements:
162
+ - - ">="
163
+ - !ruby/object:Gem::Version
164
+ version: '0'
165
+ requirements: []
166
+ rubyforge_project:
167
+ rubygems_version: 2.7.6
168
+ signing_key:
169
+ specification_version: 4
170
+ summary: Splits database ranges into lower and upper attributes in ActiveRecord
171
+ test_files: []