key_struct 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +20 -0
- data/README.rdoc +71 -0
- data/Rakefile +7 -0
- data/key_struct.gemspec +25 -0
- data/lib/key_struct.rb +36 -0
- data/lib/key_struct/version.rb +3 -0
- data/spec/key_struct_spec.rb +112 -0
- data/spec/spec_helper.rb +16 -0
- metadata +98 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Ronen Barzel
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
= key_struct
|
2
|
+
|
3
|
+
Defines KeyStruct, which is the same as ruby's Struct, but the initializer
|
4
|
+
takes keyword args (using a hash, rails-style). Use it to define a class via:
|
5
|
+
|
6
|
+
Name = KeyStruct[:first, :last]
|
7
|
+
|
8
|
+
or as an anonymous base class for your own enhanced struct:
|
9
|
+
|
10
|
+
class Name < KeyStruct[:first, :last]
|
11
|
+
def to_s
|
12
|
+
"#{@last}, #{@first}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
Then you can create an instance of the class using keywords for the parameters:
|
17
|
+
|
18
|
+
name = Name.new(:first => "Jack", :last => "Ripper")
|
19
|
+
|
20
|
+
and you have the usal readers and writers:
|
21
|
+
|
22
|
+
name.first --> "Jack"
|
23
|
+
name.last --> "Ripper"
|
24
|
+
name.last = "Sprat"
|
25
|
+
name.last --> "Sprat"
|
26
|
+
name.to_s --> "Sprat, Jack" for the enhanced class example
|
27
|
+
|
28
|
+
If you leave off a keyword when instantiating, normally the value is nil:
|
29
|
+
|
30
|
+
name = Name.new(:first => "Jack")
|
31
|
+
name.last --> nil
|
32
|
+
|
33
|
+
But the class definition can specify defaults, e.g.
|
34
|
+
|
35
|
+
Name = KeyStruct[:first, :last => "Doe"]
|
36
|
+
name = Name.new(:first => "John")
|
37
|
+
name.first --> "John"
|
38
|
+
name.last --> "Doe"
|
39
|
+
|
40
|
+
The struct initializer checks for invalid arguments:
|
41
|
+
|
42
|
+
name = Name.new(:middle => "Xaviar") --> raises ArgumentError
|
43
|
+
|
44
|
+
The gem actually provides two types of KeyStruct classes
|
45
|
+
|
46
|
+
KeyStruct.accesor(*keys) # aliased as KeyStruct[]
|
47
|
+
KeyStruct.reader(*keys) # class has readers but not writers
|
48
|
+
|
49
|
+
== Tested on
|
50
|
+
|
51
|
+
MRI 1.9.2, 1.9.3
|
52
|
+
|
53
|
+
== History
|
54
|
+
|
55
|
+
Future: I hope that this gem will be obviated in future versions of ruby.
|
56
|
+
|
57
|
+
== Note on Patches/Pull Requests
|
58
|
+
|
59
|
+
* Fork the project.
|
60
|
+
* Make your feature addition or bug fix.
|
61
|
+
* Add tests for it. This is important so I don't break it in a
|
62
|
+
future version unintentionally. Make sure that the coverage report
|
63
|
+
(generated automatically when you run rspec) is at 100%
|
64
|
+
* Commit, do not mess with Rakefile, version, or history.
|
65
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
66
|
+
* Send me a pull request.
|
67
|
+
|
68
|
+
== Copyright
|
69
|
+
|
70
|
+
Released under the MIT License. See LICENSE for details.
|
71
|
+
|
data/Rakefile
ADDED
data/key_struct.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/key_struct/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["ronen barzel"]
|
6
|
+
gem.email = ["ronen@barzel.org"]
|
7
|
+
gem.description = %q{Defines KeyStruct analogous to Struct, but constructor takes keyword arguments}
|
8
|
+
gem.summary = %q{Defines KeyStruct analogous to Struct, but constructor takes keyword arguments}
|
9
|
+
gem.homepage = 'http://github.com/ronen/key_struct'
|
10
|
+
gem.extra_rdoc_files = [
|
11
|
+
'LICENSE',
|
12
|
+
'README.rdoc',
|
13
|
+
]
|
14
|
+
|
15
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
16
|
+
gem.files = `git ls-files`.split("\n")
|
17
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
gem.name = "key_struct"
|
19
|
+
gem.require_paths = ["lib"]
|
20
|
+
gem.version = KeyStruct::VERSION
|
21
|
+
|
22
|
+
gem.add_development_dependency 'rspec'
|
23
|
+
gem.add_development_dependency 'simplecov'
|
24
|
+
gem.add_development_dependency 'simplecov-gem-adapter'
|
25
|
+
end
|
data/lib/key_struct.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "key_struct/version"
|
2
|
+
|
3
|
+
module KeyStruct
|
4
|
+
|
5
|
+
def self.reader(*keys)
|
6
|
+
define_key_struct(:attr_reader, keys)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.accessor(*keys)
|
10
|
+
define_key_struct(:attr_accessor, keys)
|
11
|
+
end
|
12
|
+
|
13
|
+
instance_eval do
|
14
|
+
alias :[] :accessor
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def self.define_key_struct(access, keys)
|
20
|
+
klass = Class.new
|
21
|
+
klass.class_eval do
|
22
|
+
keyvalues = Hash[*keys.map{|key| (Hash === key) ? key.to_a : [key, nil]}.flatten]
|
23
|
+
keys = keyvalues.keys
|
24
|
+
send access, *keys
|
25
|
+
define_method(:initialize) do |args={}|
|
26
|
+
args = keyvalues.merge(args)
|
27
|
+
keys.each do |key|
|
28
|
+
instance_variable_set("@#{key}", args.delete(key))
|
29
|
+
end
|
30
|
+
raise ArgumentError, "Invalid argument(s): #{args.keys.map(&:inspect).join(' ')}; KeyStruct accepts #{keys.map(&:inspect).join(' ')}" if args.any?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
klass
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "KeyStruct" do
|
4
|
+
|
5
|
+
it "creates a class using KeyStruct.accessor" do
|
6
|
+
Class.should === KeyStruct.accessor(:a, :b, :c => 3)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "creates a class using KeyStruct.reader" do
|
10
|
+
Class.should === KeyStruct.reader(:a, :b, :c => 3)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "creates a class using KeyStruct[]" do
|
14
|
+
Class.should === KeyStruct[:a, :b, :c => 3]
|
15
|
+
end
|
16
|
+
|
17
|
+
it "[] should be an alias for accessor" do
|
18
|
+
KeyStruct.method(:[]).should == KeyStruct.method(:accessor)
|
19
|
+
end
|
20
|
+
|
21
|
+
context "reader" do
|
22
|
+
before(:all) do
|
23
|
+
@klass = KeyStruct.reader(:a, :b, :c => 3)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "provides getters" do
|
27
|
+
@klass.instance_methods.should include(:a)
|
28
|
+
@klass.instance_methods.should include(:b)
|
29
|
+
@klass.instance_methods.should include(:c)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not provide setters" do
|
33
|
+
@klass.instance_methods.should_not include(:"a=")
|
34
|
+
@klass.instance_methods.should_not include(:"b=")
|
35
|
+
@klass.instance_methods.should_not include(:"c=")
|
36
|
+
end
|
37
|
+
|
38
|
+
it "initializer accepts all key args" do
|
39
|
+
expect { @klass.new(:a => 1, :b => 2, :c => 3) }.should_not raise_error
|
40
|
+
end
|
41
|
+
|
42
|
+
it "initializer accepts some key args" do
|
43
|
+
expect { @klass.new(:a => 1) }.should_not raise_error
|
44
|
+
end
|
45
|
+
|
46
|
+
it "initializer accepts no args" do
|
47
|
+
expect { @klass.new }.should_not raise_error
|
48
|
+
end
|
49
|
+
|
50
|
+
it "initializer raises error for invalid args" do
|
51
|
+
expect { @klass.new(:d => 4) }.should raise_error
|
52
|
+
end
|
53
|
+
|
54
|
+
it "getters returns initial/default argument values" do
|
55
|
+
reader = @klass.new(:a => 1)
|
56
|
+
reader.a.should == 1
|
57
|
+
reader.b.should be_nil
|
58
|
+
reader.c.should == 3
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context "accessor" do
|
63
|
+
before(:all) do
|
64
|
+
@klass = KeyStruct.accessor(:a, :b, :c => 3)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "provides getters" do
|
68
|
+
@klass.instance_methods.should include(:a)
|
69
|
+
@klass.instance_methods.should include(:b)
|
70
|
+
@klass.instance_methods.should include(:c)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "provides setters" do
|
74
|
+
@klass.instance_methods.should include(:"a=")
|
75
|
+
@klass.instance_methods.should include(:"b=")
|
76
|
+
@klass.instance_methods.should include(:"c=")
|
77
|
+
end
|
78
|
+
|
79
|
+
it "initializer accepts all key args" do
|
80
|
+
expect { @klass.new(:a => 1, :b => 2, :c => 3) }.should_not raise_error
|
81
|
+
end
|
82
|
+
|
83
|
+
it "initializer accepts some key args" do
|
84
|
+
expect { @klass.new(:a => 1) }.should_not raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
it "initializer accepts no args" do
|
88
|
+
expect { @klass.new }.should_not raise_error
|
89
|
+
end
|
90
|
+
|
91
|
+
it "initializer raises error for invalid args" do
|
92
|
+
expect { @klass.new(:d => 4) }.should raise_error
|
93
|
+
end
|
94
|
+
|
95
|
+
it "getters return initial argument values" do
|
96
|
+
reader = @klass.new(:a => 1)
|
97
|
+
reader.a.should == 1
|
98
|
+
reader.b.should be_nil
|
99
|
+
reader.c.should == 3
|
100
|
+
end
|
101
|
+
|
102
|
+
it "setters work as expected" do
|
103
|
+
reader = @klass.new(:a => 1)
|
104
|
+
reader.b = 2
|
105
|
+
reader.c = 4
|
106
|
+
reader.a.should == 1
|
107
|
+
reader.b.should == 2
|
108
|
+
reader.c.should == 4
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
if RUBY_VERSION > "1.9"
|
2
|
+
require 'simplecov'
|
3
|
+
require 'simplecov-gem-adapter'
|
4
|
+
SimpleCov.start 'gem'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rspec'
|
8
|
+
require 'key_struct'
|
9
|
+
|
10
|
+
# Requires supporting files with custom matchers and macros, etc,
|
11
|
+
# in ./support/ and its subdirectories.
|
12
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
13
|
+
|
14
|
+
RSpec.configure do |config|
|
15
|
+
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: key_struct
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- ronen barzel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-11-18 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :development
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: simplecov
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: simplecov-gem-adapter
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
description: Defines KeyStruct analogous to Struct, but constructor takes keyword arguments
|
49
|
+
email:
|
50
|
+
- ronen@barzel.org
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files:
|
56
|
+
- LICENSE
|
57
|
+
- README.rdoc
|
58
|
+
files:
|
59
|
+
- .gitignore
|
60
|
+
- Gemfile
|
61
|
+
- LICENSE
|
62
|
+
- README.rdoc
|
63
|
+
- Rakefile
|
64
|
+
- key_struct.gemspec
|
65
|
+
- lib/key_struct.rb
|
66
|
+
- lib/key_struct/version.rb
|
67
|
+
- spec/key_struct_spec.rb
|
68
|
+
- spec/spec_helper.rb
|
69
|
+
homepage: http://github.com/ronen/key_struct
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: "0"
|
83
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
84
|
+
none: false
|
85
|
+
requirements:
|
86
|
+
- - ">="
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: "0"
|
89
|
+
requirements: []
|
90
|
+
|
91
|
+
rubyforge_project:
|
92
|
+
rubygems_version: 1.8.11
|
93
|
+
signing_key:
|
94
|
+
specification_version: 3
|
95
|
+
summary: Defines KeyStruct analogous to Struct, but constructor takes keyword arguments
|
96
|
+
test_files:
|
97
|
+
- spec/key_struct_spec.rb
|
98
|
+
- spec/spec_helper.rb
|