key_struct 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -3,6 +3,7 @@
3
3
  .bundle
4
4
  .config
5
5
  .yardoc
6
+ .rspec
6
7
  Gemfile.lock
7
8
  InstalledFiles
8
9
  _yardoc
@@ -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
- Class.new.class_eval do
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 = keyvalues.merge(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(' ')}; KeyStruct accepts #{keys.map(&:inspect).join(' ')}" if args.any?
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
- self
60
+
50
61
  end
62
+ }
51
63
  end
52
64
 
53
65
  end
@@ -1,3 +1,3 @@
1
1
  module KeyStruct
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -1,83 +1,29 @@
1
1
  require 'spec_helper'
2
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
3
+ shared_examples "a keystruct" do |method|
12
4
 
13
- it "creates a class using KeyStruct[]" do
14
- Class.should === KeyStruct[:a, :b, :c => 3]
15
- end
5
+ context "basic" do
16
6
 
17
- it "can handle a default that's an array" do
18
- expect { KeyStruct.reader(:a => []) }.should_not raise_error
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 "provides getters" do
31
- @klass.instance_methods.should include(:a)
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 "does not provide setters" do
37
- @klass.instance_methods.should_not include(:"a=")
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 "initializer accepts all key args" do
43
- expect { @klass.new(:a => 1, :b => 2, :c => 3) }.should_not raise_error
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(:a)
73
- @klass.instance_methods.should include(:b)
74
- @klass.instance_methods.should include(:c)
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 return initial argument values" do
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
- before(:all) do
118
- @klass = KeyStruct.accessor(:a, :b, :c)
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.accessor(:a => 3, :b => 4).new.to_hash.should == {:a => 3, :b => 4}
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.accessor(:a => 3, :b => [[1,2], [3,4]]).new.to_hash.should == {:a => 3, :b => [[1,2],[3,4]]}
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
- PrintMe = KeyStruct[:a => 3, :b => "hello"]
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
- PrintMe.new.to_s.should == "[PrintMe a:3 b:hello]"
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
- PrintMe.new.inspect.should match /<PrintMe:0x[0-9a-f]+ a:3 b:"hello">/
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.3.1
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-01-20 00:00:00.000000000 Z
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: &70145079063240 !ruby/object:Gem::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: *70145079063240
24
+ version_requirements: *70338235182700
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: simplecov
27
- requirement: &70145079062540 !ruby/object:Gem::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: *70145079062540
35
+ version_requirements: *70338235177160
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: simplecov-gem-adapter
38
- requirement: &70145079062020 !ruby/object:Gem::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: *70145079062020
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.12
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