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 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