value_class 0.1.0.pre.prerelease2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: e3ea3aec695d36750ca2629b6348ae5ea195f7d0225b415051b2bf6df665faf5
4
+ data.tar.gz: d90ca345053f89ff2f3db5ea88ee5ea887aa4ca1633743cb09eff1e6c40391cb
5
+ SHA512:
6
+ metadata.gz: 56047ca389a9e46e4d78498e1b65906363efb0ff20942389157504a7044ae9e508d7b9e74adcc57c533b15c524103502fb4b2e804d86301c7bcc794af97c0379
7
+ data.tar.gz: 3549fe478d4177a84cd2f97c5863f60e17b192a074acdc95c0f5c37f4acde03ffc320e4d7a8c3e385ac2e1811ab5bbe521c7618e5b2bb066324acd971e8f9b69
data/.gitignore ADDED
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.idea/
10
+ spec/reports/*
11
+ .rubocop-http*
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/groovy
2
+ @Library('jenkins-pipeline@v0.4.5')
3
+ import com.invoca.docker.*;
4
+
5
+ pipeline {
6
+ agent {
7
+ kubernetes {
8
+ defaultContainer "ruby"
9
+ yamlFile ".jenkins/ruby_build_pod.yml"
10
+ }
11
+ }
12
+
13
+ environment {
14
+ GITHUB_TOKEN = credentials('github_token')
15
+ GITHUB_KEY = credentials('github_key')
16
+ BUNDLE_GEM__FURY__IO = credentials('gemfury_deploy_token')
17
+ }
18
+
19
+ stages {
20
+ stage('Setup') {
21
+ steps {
22
+ script {
23
+ sh '''
24
+ # get SSH setup inside the container
25
+ eval `ssh-agent -s`
26
+ echo "$GITHUB_KEY" | ssh-add -
27
+ mkdir -p /root/.ssh
28
+ ssh-keyscan -t rsa github.com > /root/.ssh/known_hosts
29
+ bundle install
30
+ '''
31
+ }
32
+ }
33
+ }
34
+
35
+ stage('Unit Test') {
36
+ steps {
37
+ script {
38
+ sh 'bundle exec rspec --format RspecJunitFormatter --out spec/reports/rspec.xml'
39
+ }
40
+ }
41
+
42
+ post {
43
+ always { junit 'spec/reports/rspec.xml' }
44
+ success { updateGitHubStatus('clean-build', 'success', 'Unit tests.') }
45
+ failure { updateGitHubStatus('clean-build', 'failure', 'Unit tests.') }
46
+ }
47
+ }
48
+ }
49
+ }
50
+
51
+ void updateGitHubStatus(String context, String status, String description) {
52
+ gitHubStatus([
53
+ repoSlug: 'Invoca/value_class',
54
+ sha: env.GIT_COMMIT,
55
+ description: description,
56
+ context: context,
57
+ targetURL: env.BUILD_URL,
58
+ token: env.GITHUB_TOKEN,
59
+ status: status
60
+ ])
61
+ }
@@ -0,0 +1,19 @@
1
+ ---
2
+ apiVersion: v1
3
+ kind: Pod
4
+ metadata:
5
+ labels:
6
+ jenkins/active-table-set: 'true'
7
+ namespace: jenkins
8
+ name: active-table-set
9
+ spec:
10
+ containers:
11
+ - name: ruby
12
+ image: ruby:2.6.1
13
+ tty: true
14
+ resources:
15
+ requests:
16
+ memory: "100Mi"
17
+ command:
18
+ - cat
19
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ # This rubocop config file inherits from our centralized style-guide repository.
2
+ # If you are looking to update the ruby style guide, be sure to both update the rubocop config
3
+ # as well as the README.md
4
+ # https://github.com/Invoca/style-guide/tree/master/ruby
5
+ inherit_from: https://raw.githubusercontent.com/Invoca/style-guide/master/ruby/.rubocop.yml
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.1
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.2
data/CHANGELOG.md ADDED
@@ -0,0 +1,11 @@
1
+ # CHANGELOG for `value_class`
2
+
3
+ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4
+
5
+ Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.0]
8
+
9
+ ### Changed
10
+
11
+ - Cloned from Active Table Set
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+ source 'https://gem.fury.io/invoca'
3
+
4
+ # Specify your gem's dependencies in value_class.gemspec
5
+ gemspec
6
+
7
+ group :development do
8
+ gem 'bundler', '~> 1.8'
9
+ gem 'pry'
10
+ gem 'pry-byebug'
11
+ gem 'rake', '~> 13.0'
12
+ gem 'rspec', '~> 3.7'
13
+ gem 'rspec-mocks', '~> 3.7'
14
+ gem 'rspec_junit_formatter'
15
+ gem 'rubocop', '0.74.0'
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,69 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ value_class (0.1.0.pre.prerelease2)
5
+ attr_comparable
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ remote: https://gem.fury.io/invoca/
10
+ specs:
11
+ ast (2.4.0)
12
+ attr_comparable (0.2.0)
13
+ byebug (10.0.2)
14
+ coderay (1.1.2)
15
+ diff-lcs (1.3)
16
+ jaro_winkler (1.5.4)
17
+ method_source (0.9.0)
18
+ parallel (1.19.1)
19
+ parser (2.7.1.1)
20
+ ast (~> 2.4.0)
21
+ pry (0.11.3)
22
+ coderay (~> 1.1.0)
23
+ method_source (~> 0.9.0)
24
+ pry-byebug (3.6.0)
25
+ byebug (~> 10.0)
26
+ pry (~> 0.10)
27
+ rainbow (3.0.0)
28
+ rake (13.0.1)
29
+ rspec (3.7.0)
30
+ rspec-core (~> 3.7.0)
31
+ rspec-expectations (~> 3.7.0)
32
+ rspec-mocks (~> 3.7.0)
33
+ rspec-core (3.7.1)
34
+ rspec-support (~> 3.7.0)
35
+ rspec-expectations (3.7.0)
36
+ diff-lcs (>= 1.2.0, < 2.0)
37
+ rspec-support (~> 3.7.0)
38
+ rspec-mocks (3.7.0)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.7.0)
41
+ rspec-support (3.7.1)
42
+ rspec_junit_formatter (0.4.1)
43
+ rspec-core (>= 2, < 4, != 2.12.0)
44
+ rubocop (0.74.0)
45
+ jaro_winkler (~> 1.5.1)
46
+ parallel (~> 1.10)
47
+ parser (>= 2.6)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ ruby-progressbar (~> 1.7)
50
+ unicode-display_width (>= 1.4.0, < 1.7)
51
+ ruby-progressbar (1.10.1)
52
+ unicode-display_width (1.6.1)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ bundler (~> 1.8)
59
+ pry
60
+ pry-byebug
61
+ rake (~> 13.0)
62
+ rspec (~> 3.7)
63
+ rspec-mocks (~> 3.7)
64
+ rspec_junit_formatter
65
+ rubocop (= 0.74.0)
66
+ value_class!
67
+
68
+ BUNDLED WITH
69
+ 1.17.2
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # ValueClass
2
+
3
+ Provides a simple mechanism for declaring a class with complex attributes. Instances of the class can be progressively
4
+ constructed in a using a block. The class is immutable outside of the block. This is useful for building simple
5
+ configuration DSLs.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'value_class'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle install
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install value_class
22
+
23
+ ## Usage
24
+
25
+ The following class declaration allow a bicycle to be declared:
26
+
27
+ ```ruby
28
+ class BikeTire
29
+ include ValueClass::Constructable
30
+
31
+ value_attr :diameter, description: "The diameter in inches"
32
+ value_attr :tred, description: "The tred on the tire"
33
+ end
34
+
35
+ class BikeSeat
36
+ include ValueClass::Constructable
37
+
38
+ value_attr :size, description: "The size of the bike seat in inches"
39
+ value_attr :color
40
+ end
41
+
42
+ class Bicycle
43
+ include ValueClass::Constructable
44
+
45
+ value_description "For riding around town"
46
+ value_attr :speeds
47
+ value_attr :color, default: :orange
48
+ value_attr :seat, class_name: 'BikeSeat'
49
+
50
+ value_list_attr :riders, insert_method: :add_rider
51
+ value_list_attr :tires, insert_method: :tire, class_name: 'BikeTire'
52
+ end
53
+ ```
54
+
55
+ Given the above declarations, you can then configure a bicycle with the following code.
56
+
57
+ ```ruby
58
+ bike = Bicycle.config do |bicycle|
59
+ bicycle.speeds 10
60
+ bicycle.color :blue
61
+ bicycle.seat do |seat|
62
+ seat.color :green
63
+ seat.size :large
64
+ end
65
+ end
66
+ ```
67
+
68
+ You can also directly declare the class:
69
+
70
+ ```ruby
71
+ bike = Bicycle.new(speeds: 10, color: :gold, tires: [{ diameter: 40, tred: :mountain }, { diameter: 50, tred: :slicks }])
72
+ ```
73
+
74
+ If you have a simple class, ValueClass provides a replacement for ruby struct that allows for a quick class declaration.
75
+
76
+ ```ruby
77
+
78
+ Gears = ValueClass.struct(:first_gear, :second_gear, :third_gear, default: 200)
79
+ gear = Gears.new(first_gear: 20)
80
+ ```
81
+
82
+ Once an instance of a class is returned. It is immutable: it is frozen and all if its attributes are frozen.
83
+
84
+ ### Running Tests
85
+
86
+ Tests in this gem are written in Rspec and can be executed through the main rake task for the repo
87
+ ```bash
88
+ bundle exec rake
89
+ ```
90
+
91
+ If there is a subset of tests you would like to run, you can add the `focus: true` tag to the test or context to only run the subset of tests.
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork it ( https://github.com/invoca/value_class/fork )
96
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
97
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
98
+ 4. Push to the branch (`git push origin my-new-feature`)
99
+ 4. Make sure the tests pass: `rspec spec`
100
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
4
+ require 'rspec/core/rake_task'
5
+
6
+ Bundler::GemHelper.install_tasks
7
+
8
+ RSpec::Core::RakeTask.new(:spec)
9
+
10
+ task :rubocop do
11
+ puts "rubocop"
12
+ rubocop_output = `rubocop -a app lib test`
13
+ print rubocop_output
14
+ unless rubocop_output.match(/files inspected, no offenses detected/)
15
+ exit 1
16
+ end
17
+ end
18
+
19
+ task default: [:spec, :rubocop]
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValueClass
4
+ class Attribute
5
+ attr_reader :name, :options, :limit
6
+
7
+ OPTIONS = {
8
+ description: "A description of the attribute.",
9
+ default: "The default value for this parameter.",
10
+ class_name: "The name of the value class for this attribute. Allows for construction from a nested hash.",
11
+ list_of_class: "Used to declare an attribute that is a list of a class.",
12
+ required: "If true, the parameter is required",
13
+ limit: "The set of valid values",
14
+ insert_method: "The name of the method to create to allow inserting into a list during progressive construction"
15
+ }.freeze
16
+
17
+ def initialize(name, options)
18
+ if (invalid_options = options.keys - OPTIONS.keys).any?
19
+ raise ArgumentError, "Unknown option(s): #{invalid_options.join(',')}"
20
+ end
21
+
22
+ @name = name.to_sym.freeze
23
+ @options = options.freeze
24
+ @limit = options[:limit]
25
+ end
26
+
27
+ def description(prefix = "")
28
+ if options[:description]
29
+ "#{prefix}#{name}: #{options[:description]}"
30
+ else
31
+ "#{prefix}#{name}"
32
+ end
33
+ end
34
+
35
+ def get_value(config)
36
+ raw_value = raw_value(config)
37
+
38
+ cast_value = cast_value(raw_value)
39
+
40
+ if cast_value.nil? && options[:required]
41
+ raise ArgumentError, "must provide a value for #{name}"
42
+ end
43
+
44
+ if !cast_value.nil? && limit && !limit.include?(cast_value)
45
+ raise ArgumentError, "invalid value #{cast_value.inspect} for #{name}. allowed values #{limit.inspect}"
46
+ end
47
+
48
+ if cast_value.nil?
49
+ default
50
+ else
51
+ cast_value
52
+ end
53
+ end
54
+
55
+ def hash_value(raw_value)
56
+ if options[:list_of_class] && raw_value.is_a?(Array)
57
+ raw_value.map(&:to_hash)
58
+ elsif options[:class_name] && raw_value
59
+ raw_value.to_hash
60
+ else
61
+ raw_value
62
+ end
63
+ end
64
+
65
+ def default
66
+ value = options[:default]
67
+ begin
68
+ value.dup
69
+ rescue TypeError
70
+ value
71
+ end
72
+ end
73
+
74
+ private
75
+
76
+ def cast_value(raw_value)
77
+ if options[:list_of_class] && raw_value.is_a?(Array)
78
+ inner_class = options[:list_of_class]
79
+ raw_value.map { |v| Object.const_get(inner_class).new(v).freeze }
80
+ elsif options[:class_name] && raw_value
81
+ Object.const_get(options[:class_name]).new(raw_value).freeze
82
+ else
83
+ raw_value
84
+ end
85
+ end
86
+
87
+ def raw_value(config)
88
+ if config.is_a?(Hash)
89
+ config[name]
90
+ else
91
+ config.send(name)
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValueClass
4
+ module Constructable
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ base.include(ValueClass)
8
+ end
9
+
10
+ def clone_config
11
+ config = self.class.config_class.new
12
+ self.class.value_attributes.each do |attr|
13
+ current_value = send(attr.name)
14
+ dup_value =
15
+ begin
16
+ current_value.dup
17
+ rescue TypeError
18
+ current_value
19
+ end
20
+ config.send("#{attr.name}=", dup_value)
21
+ end
22
+ yield config
23
+ self.class.new(config)
24
+ end
25
+
26
+ module ClassMethods
27
+ # Constructs an instance using the configuration created in the passed in block.
28
+ def config
29
+ config = config_class.new
30
+ value_attributes.each do |attr|
31
+ if attr.default
32
+ config.send("#{attr.name}=", attr.default)
33
+ end
34
+ end
35
+ yield config
36
+ new(config)
37
+ end
38
+
39
+ def config_class
40
+ unless @config_class
41
+ @config_class = Class.new
42
+
43
+ value_attributes.each do |attribute|
44
+ # Define assignment operator
45
+ @config_class.send(:attr_writer, attribute.name)
46
+
47
+ define_accessor(attribute)
48
+ if (insert_method = attribute.options[:insert_method])
49
+ define_insert(attribute, insert_method)
50
+ end
51
+ end
52
+ end
53
+ @config_class
54
+ end
55
+
56
+ private
57
+
58
+ def define_insert(attribute, insert_method)
59
+ if (class_name = attribute.options[:list_of_class])
60
+ config_class.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
61
+ def #{insert_method}(value=nil, &blk)
62
+ if blk
63
+ @#{attribute.name} << #{class_name}.config { |config| yield config }
64
+ else
65
+ @#{attribute.name} << #{class_name}.new(value)
66
+ end
67
+ @#{attribute.name}
68
+ end
69
+ EORUBY
70
+ else
71
+ config_class.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
72
+ def #{insert_method}(value)
73
+ @#{attribute.name} << value
74
+ @#{attribute.name}
75
+ end
76
+ EORUBY
77
+ end
78
+ end
79
+
80
+ def define_accessor(attribute)
81
+ if (class_name = attribute.options[:class_name])
82
+ config_class.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
83
+ def #{attribute.name}(&blk)
84
+ if blk
85
+ @#{attribute.name} = #{class_name}.config { |config| yield config }
86
+ end
87
+ @#{attribute.name}
88
+ end
89
+ EORUBY
90
+ else
91
+ config_class.class_eval <<-EORUBY, __FILE__, __LINE__ + 1
92
+ def #{attribute.name}(value = nil)
93
+ unless value.nil?
94
+ @#{attribute.name} = value
95
+ end
96
+ @#{attribute.name}
97
+ end
98
+ EORUBY
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ValueClass
4
+ VERSION = "0.1.0-prerelease2"
5
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'attr_comparable'
4
+ require 'value_class/attribute'
5
+
6
+ module ValueClass
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ # Default constructor
12
+ def initialize(config = {})
13
+ check_constructor_params(config)
14
+ self.class.declare_comparison_operators
15
+ self.class.value_attributes.each do |attribute|
16
+ instance_variable_set("@#{attribute.name}", attribute.get_value(config).freeze)
17
+ end
18
+ end
19
+
20
+ # TODO: These need to be added to attr_comparible
21
+ def eql?(other)
22
+ self == other
23
+ end
24
+
25
+ def hash
26
+ self.class.value_attributes.map do |attribute|
27
+ instance_variable_get("@#{attribute.name}")
28
+ end.hash
29
+ end
30
+
31
+ def to_hash
32
+ self.class.value_attributes.each_with_object({}) do |attribute, hash|
33
+ # Attributes are frozen, but hash with indifferent access mutates values (!!!), so we have to dup
34
+ # in order to get a value we can use
35
+ unsafe_version = attribute.hash_value(instance_variable_get("@#{attribute.name}"))
36
+ safe_version =
37
+ begin
38
+ unsafe_version.dup
39
+ rescue TypeError
40
+ unsafe_version
41
+ end
42
+
43
+ hash[attribute.name.to_sym] = safe_version
44
+ end
45
+ end
46
+
47
+ def self.struct(*args)
48
+ Class.new do
49
+ include ValueClass::Constructable
50
+ value_attrs(*args)
51
+ end
52
+ end
53
+
54
+ protected
55
+
56
+ def check_constructor_params(config)
57
+ if config.is_a?(Hash)
58
+ extra_keys = config.keys - self.class.value_attributes.map(&:name)
59
+ extra_keys.empty? or raise ArgumentError, "unknown attribute #{extra_keys.join(', ')}"
60
+ end
61
+ end
62
+
63
+ module ClassMethods
64
+ def value_description(value = nil)
65
+ if value
66
+ @value_description = value
67
+ end
68
+ @value_description
69
+ end
70
+
71
+ def value_list_attr(attribute_name, options = {})
72
+ value_attr(attribute_name, options.merge(default: [], class_name: nil, list_of_class: options[:class_name]))
73
+ end
74
+
75
+ def value_attr(attribute_name, options = {})
76
+ attribute = Attribute.new(attribute_name, options)
77
+ value_attributes << attribute
78
+
79
+ attr_reader(attribute.name)
80
+ end
81
+
82
+ def value_attrs(*args)
83
+ options = args.last.is_a?(::Hash) ? args.pop : {}
84
+ args.each { |arg| value_attr(arg, options) }
85
+ end
86
+
87
+ def config_help(prefix = "")
88
+ [
89
+ "#{name}: #{value_description}",
90
+ " attributes:",
91
+ value_attributes.map { |ca| ca.description(prefix + " ") }
92
+ ].flatten.join("\n") + "\n"
93
+ end
94
+
95
+ def value_attributes
96
+ @value_attributes ||= []
97
+ end
98
+
99
+ def declare_comparison_operators
100
+ unless @comparison_operators_declared
101
+ @comparison_operators_declared = true
102
+
103
+ include AttrComparable
104
+ attr_compare(value_attributes.map(&:name))
105
+ end
106
+ end
107
+
108
+ def inherited(new_child_class)
109
+ value_attributes.each { |attr| new_child_class.value_attributes << attr }
110
+ end
111
+ end
112
+ end
113
+
114
+ # These build off of the above, so they are required last
115
+ require 'value_class/constructable'
@@ -0,0 +1,21 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'value_class/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "value_class"
7
+ spec.version = ValueClass::VERSION
8
+ spec.authors = ["Bob Smith"]
9
+ spec.email = ["bob@invoca.com"]
10
+
11
+ spec.summary = %q{ValueClass a lightweight way to define configuration DSLs.}
12
+ spec.description = %q{ValueClass provides an interface to declare simple classes that can be progressively constructed but that are imutable afterwards.}
13
+ spec.homepage = "https://github.com/invoca/value_class"
14
+ spec.license = ""
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_dependency 'attr_comparable'
21
+ end
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: value_class
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.pre.prerelease2
5
+ platform: ruby
6
+ authors:
7
+ - Bob Smith
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: attr_comparable
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: ValueClass provides an interface to declare simple classes that can be
28
+ progressively constructed but that are imutable afterwards.
29
+ email:
30
+ - bob@invoca.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - ".gitignore"
36
+ - ".jenkins/Jenkinsfile"
37
+ - ".jenkins/ruby_build_pod.yml"
38
+ - ".rspec"
39
+ - ".rubocop.yml"
40
+ - ".ruby-version"
41
+ - ".travis.yml"
42
+ - CHANGELOG.md
43
+ - Gemfile
44
+ - Gemfile.lock
45
+ - README.md
46
+ - Rakefile
47
+ - lib/value_class.rb
48
+ - lib/value_class/attribute.rb
49
+ - lib/value_class/constructable.rb
50
+ - lib/value_class/version.rb
51
+ - value_class.gemspec
52
+ homepage: https://github.com/invoca/value_class
53
+ licenses:
54
+ - ''
55
+ metadata: {}
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.3.1
70
+ requirements: []
71
+ rubygems_version: 3.0.1
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: ValueClass a lightweight way to define configuration DSLs.
75
+ test_files: []