key_struct 0.3.1 → 0.4.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.
- data/.gitignore +1 -0
- data/README.rdoc +9 -0
- data/lib/key_struct/key_struct.rb +18 -6
- data/lib/key_struct/version.rb +1 -1
- data/spec/key_struct_spec.rb +84 -83
- metadata +9 -9
data/.gitignore
CHANGED
data/README.rdoc
CHANGED
@@ -108,6 +108,14 @@ all members and their values:
|
|
108
108
|
|
109
109
|
Name.new(:first => "Jack", :last => "Ripper").to_hash # --> {:first => "Jack", :last => "Ripper")
|
110
110
|
|
111
|
+
== Introspection
|
112
|
+
|
113
|
+
KeyStruct classes let you examine their definition:
|
114
|
+
|
115
|
+
Name = KeyStruct[:first, :last => "Doe"]
|
116
|
+
Name.keys # --> [ :first, :last ]
|
117
|
+
Name.defaults # --> { :last => "Doe" }
|
118
|
+
|
111
119
|
== Installation
|
112
120
|
|
113
121
|
Install via:
|
@@ -126,6 +134,7 @@ Requires ruby >= 1.9.2. (Has been tested on MRI 1.9.2 and MRI 1.9.3)
|
|
126
134
|
|
127
135
|
Release Notes:
|
128
136
|
|
137
|
+
* 0.4.0 - Introduce class introspection
|
129
138
|
* 0.3.1 - Bug fix: to_hash when a value is an array. Was raising ArgumentError for Hash
|
130
139
|
* 0.3.0 - Introduced to_s and inspect
|
131
140
|
* 0.2.1 - Bug fix: return false for == with an incompatible object. Was raising NoMethodError
|
@@ -15,21 +15,29 @@ module KeyStruct
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def self.define_key_struct(access, keys)
|
18
|
-
|
18
|
+
|
19
|
+
defaults = (Hash === keys.last) ? keys.pop : {}
|
20
|
+
keys += defaults.keys
|
21
|
+
|
22
|
+
Class.new.tap{ |klass| klass.class_eval do
|
19
23
|
include Comparable
|
20
|
-
keyvalues = Hash[*keys.map{|key| (Hash === key) ? key.to_a : [key, nil]}.flatten(2)]
|
21
|
-
keys = keyvalues.keys
|
22
24
|
send access, *keys
|
25
|
+
|
26
|
+
define_singleton_method(:keys) { keys }
|
27
|
+
define_singleton_method(:defaults) { defaults }
|
28
|
+
|
23
29
|
define_method(:initialize) do |args={}|
|
24
|
-
args =
|
30
|
+
args = defaults.merge(args)
|
25
31
|
keys.each do |key|
|
26
32
|
instance_variable_set("@#{key}".to_sym, args.delete(key))
|
27
33
|
end
|
28
|
-
raise ArgumentError, "Invalid argument(s): #{args.keys.map(&:inspect).join(' ')}
|
34
|
+
raise ArgumentError, "Invalid argument(s): #{args.keys.map(&:inspect).join(' ')} -- KeyStruct accepts #{keys.map(&:inspect).join(' ')}" if args.any?
|
29
35
|
end
|
36
|
+
|
30
37
|
define_method(:==) do |other|
|
31
38
|
keys.all?{|key| other.respond_to?(key) and self.send(key) == other.send(key)}
|
32
39
|
end
|
40
|
+
|
33
41
|
define_method(:<=>) do |other|
|
34
42
|
keys.each do |key|
|
35
43
|
cmp = (self.send(key) <=> other.send(key))
|
@@ -37,17 +45,21 @@ module KeyStruct
|
|
37
45
|
end
|
38
46
|
0
|
39
47
|
end
|
48
|
+
|
40
49
|
define_method(:to_hash) do
|
41
50
|
Hash[*keys.map{ |key| [key, self.send(key)]}.flatten(1)]
|
42
51
|
end
|
52
|
+
|
43
53
|
define_method(:to_s) do
|
44
54
|
"[#{self.class.name} #{keys.map{|key| "#{key}:#{self.send(key)}"}.join(' ')}]"
|
45
55
|
end
|
56
|
+
|
46
57
|
define_method(:inspect) do
|
47
58
|
"<#{self.class.name}:0x#{self.object_id.to_s(16)} #{keys.map{|key| "#{key}:#{self.send(key).inspect}"}.join(' ')}>"
|
48
59
|
end
|
49
|
-
|
60
|
+
|
50
61
|
end
|
62
|
+
}
|
51
63
|
end
|
52
64
|
|
53
65
|
end
|
data/lib/key_struct/version.rb
CHANGED
data/spec/key_struct_spec.rb
CHANGED
@@ -1,83 +1,29 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
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
|
3
|
+
shared_examples "a keystruct" do |method|
|
12
4
|
|
13
|
-
|
14
|
-
Class.should === KeyStruct[:a, :b, :c => 3]
|
15
|
-
end
|
5
|
+
context "basic" do
|
16
6
|
|
17
|
-
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
it "[] should be an alias for accessor" do
|
22
|
-
KeyStruct.method(:[]).should == KeyStruct.method(:accessor)
|
23
|
-
end
|
24
|
-
|
25
|
-
context "reader" do
|
26
|
-
before(:all) do
|
27
|
-
@klass = KeyStruct.reader(:a, :b, :c => 3)
|
7
|
+
before(:each) do
|
8
|
+
@klass = KeyStruct.send(method, :a, :b, :c => 3)
|
28
9
|
end
|
29
10
|
|
30
|
-
it "
|
31
|
-
|
32
|
-
@klass.instance_methods.should include(:b)
|
33
|
-
@klass.instance_methods.should include(:c)
|
11
|
+
it "creates a class" do
|
12
|
+
Class.should === @klass
|
34
13
|
end
|
35
14
|
|
36
|
-
it "
|
37
|
-
@klass.
|
38
|
-
@klass.instance_methods.should_not include(:"b=")
|
39
|
-
@klass.instance_methods.should_not include(:"c=")
|
15
|
+
it "should instrospect keys" do
|
16
|
+
@klass.keys.should == [:a, :b, :c]
|
40
17
|
end
|
41
18
|
|
42
|
-
it "
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
it "initializer accepts some key args" do
|
47
|
-
expect { @klass.new(:a => 1) }.should_not raise_error
|
48
|
-
end
|
49
|
-
|
50
|
-
it "initializer accepts no args" do
|
51
|
-
expect { @klass.new }.should_not raise_error
|
52
|
-
end
|
53
|
-
|
54
|
-
it "initializer raises error for invalid args" do
|
55
|
-
expect { @klass.new(:d => 4) }.should raise_error
|
56
|
-
end
|
57
|
-
|
58
|
-
it "getters returns initial/default argument values" do
|
59
|
-
reader = @klass.new(:a => 1)
|
60
|
-
reader.a.should == 1
|
61
|
-
reader.b.should be_nil
|
62
|
-
reader.c.should == 3
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context "accessor" do
|
67
|
-
before(:all) do
|
68
|
-
@klass = KeyStruct.accessor(:a, :b, :c => 3)
|
19
|
+
it "should instrospect defaults" do
|
20
|
+
@klass.defaults.should == {:c => 3}
|
69
21
|
end
|
70
22
|
|
71
23
|
it "provides getters" do
|
72
|
-
@klass.instance_methods.should include
|
73
|
-
@klass.instance_methods.should include
|
74
|
-
@klass.instance_methods.should include
|
75
|
-
end
|
76
|
-
|
77
|
-
it "provides setters" do
|
78
|
-
@klass.instance_methods.should include(:"a=")
|
79
|
-
@klass.instance_methods.should include(:"b=")
|
80
|
-
@klass.instance_methods.should include(:"c=")
|
24
|
+
@klass.instance_methods.should include :a
|
25
|
+
@klass.instance_methods.should include :b
|
26
|
+
@klass.instance_methods.should include :c
|
81
27
|
end
|
82
28
|
|
83
29
|
it "initializer accepts all key args" do
|
@@ -96,26 +42,19 @@ describe "KeyStruct" do
|
|
96
42
|
expect { @klass.new(:d => 4) }.should raise_error
|
97
43
|
end
|
98
44
|
|
99
|
-
it "getters
|
45
|
+
it "getters returns initial/default argument values" do
|
100
46
|
reader = @klass.new(:a => 1)
|
101
47
|
reader.a.should == 1
|
102
48
|
reader.b.should be_nil
|
103
49
|
reader.c.should == 3
|
104
50
|
end
|
105
51
|
|
106
|
-
it "setters work as expected" do
|
107
|
-
reader = @klass.new(:a => 1)
|
108
|
-
reader.b = 2
|
109
|
-
reader.c = 4
|
110
|
-
reader.a.should == 1
|
111
|
-
reader.b.should == 2
|
112
|
-
reader.c.should == 4
|
113
|
-
end
|
114
52
|
end
|
115
53
|
|
116
54
|
context "comparison" do
|
117
|
-
|
118
|
-
|
55
|
+
|
56
|
+
before(:each) do
|
57
|
+
@klass = KeyStruct.send(method, :a, :b, :c)
|
119
58
|
end
|
120
59
|
|
121
60
|
it "returns true iff all members are ==" do
|
@@ -146,23 +85,85 @@ describe "KeyStruct" do
|
|
146
85
|
end
|
147
86
|
|
148
87
|
it "returns hash using to_hash" do
|
149
|
-
KeyStruct.
|
88
|
+
KeyStruct.send(method, :a => 3, :b => 4).new.to_hash.should == {:a => 3, :b => 4}
|
150
89
|
end
|
151
90
|
|
152
91
|
it "returns hash using to_hash when value is array" do
|
153
|
-
KeyStruct.
|
92
|
+
KeyStruct.send(method, :a => 3, :b => [[1,2], [3,4]]).new.to_hash.should == {:a => 3, :b => [[1,2],[3,4]]}
|
93
|
+
end
|
94
|
+
|
95
|
+
it "can handle a default that's an array" do
|
96
|
+
expect { KeyStruct.send(method, :a => []) }.should_not raise_error
|
154
97
|
end
|
155
98
|
|
156
99
|
context "display as a string" do
|
157
|
-
|
100
|
+
|
101
|
+
around(:each) do |example|
|
102
|
+
PrintMe = @klass = KeyStruct.send(method, :a => 3, :b => "hello")
|
103
|
+
example.run
|
104
|
+
Object.send(:remove_const, :PrintMe)
|
105
|
+
end
|
158
106
|
|
159
107
|
it "should be nice for :to_s" do
|
160
|
-
|
108
|
+
@klass.new.to_s.should == "[PrintMe a:3 b:hello]"
|
161
109
|
end
|
162
110
|
|
163
111
|
it "should be detailed for :inspect" do
|
164
|
-
|
112
|
+
@klass.new.inspect.should match /<PrintMe:0x[0-9a-f]+ a:3 b:"hello">/
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "KeyStruct" do
|
119
|
+
|
120
|
+
context "reader" do
|
121
|
+
|
122
|
+
it_behaves_like "a keystruct", :reader
|
123
|
+
|
124
|
+
context "basic" do
|
125
|
+
before(:each) do
|
126
|
+
@klass = KeyStruct.reader(:a, :b, :c => 3)
|
127
|
+
end
|
128
|
+
|
129
|
+
it "does not provide setters" do
|
130
|
+
@klass.instance_methods.should_not include :"a="
|
131
|
+
@klass.instance_methods.should_not include :"b="
|
132
|
+
@klass.instance_methods.should_not include :"c="
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
context "accessor" do
|
139
|
+
it_behaves_like "a keystruct", :accessor
|
140
|
+
|
141
|
+
it "[] should be an alias for accessor" do
|
142
|
+
KeyStruct.method(:[]).should == KeyStruct.method(:accessor)
|
143
|
+
end
|
144
|
+
|
145
|
+
context "basic" do
|
146
|
+
|
147
|
+
before(:each) do
|
148
|
+
@klass = KeyStruct.accessor(:a, :b, :c => 3)
|
149
|
+
end
|
150
|
+
|
151
|
+
it "does provides setters" do
|
152
|
+
@klass.instance_methods.should include :"a="
|
153
|
+
@klass.instance_methods.should include :"b="
|
154
|
+
@klass.instance_methods.should include :"c="
|
155
|
+
end
|
156
|
+
|
157
|
+
it "setters work as expected" do
|
158
|
+
reader = @klass.new(:a => 1)
|
159
|
+
reader.b = 2
|
160
|
+
reader.c = 4
|
161
|
+
reader.a.should == 1
|
162
|
+
reader.b.should == 2
|
163
|
+
reader.c.should == 4
|
164
|
+
end
|
165
165
|
end
|
166
166
|
end
|
167
167
|
|
168
|
+
|
168
169
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: key_struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &70338235182700 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70338235182700
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: simplecov
|
27
|
-
requirement: &
|
27
|
+
requirement: &70338235177160 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70338235177160
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: simplecov-gem-adapter
|
38
|
-
requirement: &
|
38
|
+
requirement: &70338235172560 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70338235172560
|
47
47
|
description: Defines KeyStruct analogous to Struct, but constructor takes keyword
|
48
48
|
arguments
|
49
49
|
email:
|
@@ -85,7 +85,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
85
|
version: '0'
|
86
86
|
requirements: []
|
87
87
|
rubyforge_project:
|
88
|
-
rubygems_version: 1.8.
|
88
|
+
rubygems_version: 1.8.10
|
89
89
|
signing_key:
|
90
90
|
specification_version: 3
|
91
91
|
summary: Defines KeyStruct analogous to Struct, but constructor takes keyword arguments
|