hash_initialized_struct 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
+ SHA1:
3
+ metadata.gz: 28eb0a537f9077e0834c71e8bc6ca52d2038c67e
4
+ data.tar.gz: f55ba4273ae166f51743a855fda5f9dcec7fece1
5
+ SHA512:
6
+ metadata.gz: 3d4498296eb6deaa2e57b3bf64629657a24d9db6d108549804012e6e4128f68922cf0ff7b76e72d3124c847d9c37a7fcd725489e4dd9dd22dfcdcf1f9bc5f3f9
7
+ data.tar.gz: 1d98179af8ca82f5d29c54929f66c4f9110a2079e488f415854aaec6d70720325dfad205a08cfb7e838e35486141cc7a66ad1d9a7fa184bde79a555a7f1f2420
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ /.bundle
2
+ /Gemfile.lock
3
+ /coverage
4
+ /pkg
5
+ /spec/reports
6
+ /tmp
7
+ *.bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in hash_initialized_struct.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2015 Rob Howard
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
4
+
5
+ http://www.apache.org/licenses/LICENSE-2.0
6
+
7
+ Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # Hash-Initialized Struct
2
+
3
+ Halfway between Struct and OpenStruct. (Or: Struct, except it takes a Hash on object initialization.)
4
+
5
+ Ignore if you already use [Virtus](https://github.com/solnic/virtus) or [Hashie::Dash](https://github.com/intridea/hashie).
6
+
7
+
8
+ ## Usage
9
+
10
+ ```ruby
11
+ class Point < HashInitializedStruct.new(:x, :y); end
12
+ # Or: Point = HashInitializedStruct.new(:x, :y)
13
+
14
+ point = Point.new(x: 1, y: 2)
15
+ point.x # => 1
16
+
17
+ unknowns = Point.new(x: 1, y: 2, z: 3)
18
+ # => raises ArgumentError, "Unrecognised keys: :z"
19
+
20
+ missing = Point.new(x: 1)
21
+ # => raises ArgumentError, "Missing keys: :y"
22
+ ```
23
+
24
+ ### Fancy Usage
25
+
26
+ ```ruby
27
+ class Point < HashInitializedStruct.new(:x, :y)
28
+ def initialize(attrs)
29
+ super
30
+ [x, y].each do |attr|
31
+ raise ArgumentError, "#{attr} must be a number" unless attr.kind_of?(Numeric)
32
+ end
33
+ end
34
+ end
35
+
36
+ good = Point.new(x: 1, y: 2)
37
+ good.x # => 1
38
+
39
+ bad = Point.new(x: "1", y: nil)
40
+ # => raises ArgumentError, "x must ..."
41
+ ```
42
+
43
+
44
+ ### Fancier Usage
45
+
46
+ Stop. Go use [Virtus](https://github.com/solnic/virtus).
47
+
48
+
49
+ ## Installation
50
+
51
+ Add the following to your application's Gemfile:
52
+
53
+ ```ruby
54
+ gem 'hash_initialized_struct'
55
+ ```
56
+
57
+ And then run `bundle install`.
58
+
59
+
60
+ ## Contributing
61
+
62
+ 1. Fork it ( https://github.com/damncabbage/hash_initialized_struct/fork )
63
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
64
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
65
+ 4. Push to the branch (`git push origin my-new-feature`)
66
+ 5. Create a new Pull Request
67
+
68
+ ## License
69
+
70
+ See LICENSE.txt
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rspec/core/rake_task"
4
+ desc "Run all specs"
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.pattern = 'spec/**/*_spec.rb'
7
+ end
8
+ task :default => :spec
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'hash_initialized_struct/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "hash_initialized_struct"
8
+ spec.version = HashInitializedStruct::VERSION
9
+ spec.authors = ["Rob Howard"]
10
+ spec.email = ["rob@robhoward.id.au"]
11
+ spec.summary = %Q{Struct, except it takes a Hash on object initialization.}
12
+ spec.description = %Q{Struct, except it takes a Hash on object initialization.\nclass Point < HashInitializedStruct.new(:x, :y); end; Point.new(x: 1, y: 2)}
13
+ spec.homepage = "https://github.com/damncabbage/hash_initialized_struct"
14
+ spec.license = "Apache 2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.2"
24
+ end
@@ -0,0 +1,3 @@
1
+ class HashInitializedStruct
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,51 @@
1
+ require "hash_initialized_struct/version"
2
+
3
+ # class Point < HashInitializedStruct(:x, :y); end
4
+ # Or: Point = HashInitializedStruct(:x, :y)
5
+ #
6
+ # point = Point.new(x: 1, y: 2)
7
+ # point.x # => 1
8
+ #
9
+ # point2 = Point.new(x: 1, y: 2, nonsense: "foobar")
10
+ # # => raises ArgumentError
11
+ class HashInitializedStruct
12
+ class << self
13
+ alias :subclass_new :new
14
+ end
15
+
16
+ def self.new(*attrs)
17
+ symbol_attrs = attrs.map do |a|
18
+ case a
19
+ when Symbol
20
+ a
21
+ else
22
+ a.to_sym.tap do |sym|
23
+ raise TypeError, "Could not coerce #{a.inspect} to symbol" unless sym.kind_of?(Symbol)
24
+ end
25
+ end
26
+ end
27
+
28
+ Class.new self do
29
+ const_set :STRUCT_ATTRS, symbol_attrs
30
+ attr_accessor *symbol_attrs
31
+
32
+ def self.new(*args, &block)
33
+ self.subclass_new(*args, &block)
34
+ end
35
+
36
+ def initialize(attrs)
37
+ provided = attrs.keys
38
+ needed = self.class::STRUCT_ATTRS
39
+ (provided - needed).tap do |unknown|
40
+ raise ArgumentError, "Unrecognised keys: #{unknown.map(&:inspect).join(', ')}" unless unknown.empty?
41
+ end
42
+ (needed - provided).tap do |missing|
43
+ raise ArgumentError, "Missing keys: #{missing.map(&:inspect).join(', ')}" unless missing.empty?
44
+ end
45
+ attrs.each do |attr,value|
46
+ instance_variable_set("@#{attr}", value)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,57 @@
1
+ require 'hash_initialized_struct'
2
+
3
+ describe "HashInitializedStruct" do
4
+ let(:klass) { HashInitializedStruct.new(:x, :y) }
5
+
6
+ it "creates a struct class that accepts initializing values via a Hash" do
7
+ point = klass.new(x: 1, y: 2)
8
+ expect(point.x).to eq 1
9
+ expect(point.y).to eq 2
10
+ end
11
+
12
+ it "creates a struct class that extends from HashInitializedStruct" do
13
+ expect(klass < HashInitializedStruct).to eq true
14
+ end
15
+
16
+ it "allows mutation of attributes" do
17
+ point = klass.new(x: 1, y: 2)
18
+ expect(point.x).to eq 1
19
+ point.x = 5
20
+ expect(point.x).to eq 5
21
+ end
22
+
23
+ it "disallows unrecognised keys" do
24
+ expect {
25
+ point = klass.new(x: 1, y: 2, z: 3)
26
+ }.to raise_error(ArgumentError, "Unrecognised keys: :z")
27
+ expect {
28
+ point = klass.new(x: 1, y: 2, self => "u wot")
29
+ }.to raise_error(ArgumentError, /Unrecognised keys: #<RSpec.*>/)
30
+ end
31
+
32
+ it "disallows creation with missing keys" do
33
+ expect {
34
+ point = klass.new(x: 1)
35
+ }.to raise_error(ArgumentError, "Missing keys: :y")
36
+ end
37
+
38
+ it "allows for overriding the constructor to add additional checks" do
39
+ # Could do this with an anonymous class and define_method, but we're trying to emulate
40
+ # how it might actually be used.
41
+ class My3DPoint < HashInitializedStruct.new(:x, :y, :z)
42
+ def initialize(attrs)
43
+ super
44
+ [x, y, z].each do |attr|
45
+ raise ArgumentError, "#{attr} must be a number" unless attr.kind_of?(Numeric)
46
+ end
47
+ end
48
+ end
49
+
50
+ good = My3DPoint.new(x: 1, y: 2, z: 9)
51
+ expect(good.x).to eq 1
52
+
53
+ expect {
54
+ My3DPoint.new(x: "1", y: nil, z: 9)
55
+ }.to raise_error(ArgumentError)
56
+ end
57
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hash_initialized_struct
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Rob Howard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-02-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ description: |-
56
+ Struct, except it takes a Hash on object initialization.
57
+ class Point < HashInitializedStruct.new(:x, :y); end; Point.new(x: 1, y: 2)
58
+ email:
59
+ - rob@robhoward.id.au
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - .gitignore
65
+ - Gemfile
66
+ - LICENSE.txt
67
+ - README.md
68
+ - Rakefile
69
+ - hash_initialized_struct.gemspec
70
+ - lib/hash_initialized_struct.rb
71
+ - lib/hash_initialized_struct/version.rb
72
+ - spec/hash_initialized_struct_spec.rb
73
+ homepage: https://github.com/damncabbage/hash_initialized_struct
74
+ licenses:
75
+ - Apache 2.0
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.0.14
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Struct, except it takes a Hash on object initialization.
97
+ test_files:
98
+ - spec/hash_initialized_struct_spec.rb