attr_plus 0.3.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,75 +2,79 @@
2
2
 
3
3
  ## ClassAttr
4
4
 
5
- Adds `#class_attr_accessor` (and reader/writer) and `#inheritable_class_attr_accessor` (and
5
+ Adds `class_attr_accessor` (and reader/writer) and `inheritable_class_attr_accessor` (and
6
6
  reader/writer of course) to Class.
7
7
 
8
- require 'attr_plus'
8
+ ``` ruby
9
+ require 'attr_plus'
9
10
 
10
- class Polygon
11
- class_attr_accessor :sides
12
- end
13
-
14
- Polygon.sides = 5
15
- Polygon.sides #=> 5
16
-
17
- class Square < Polygon
18
- end
19
-
20
- Square.sides #=> nil
21
-
22
-
23
- class InheritablePolygon
24
- inheritable_class_attr_accessor :sides
25
- end
26
-
27
- Polygon.sides = 4
28
-
29
- class NewSquare < Polygon
30
- end
31
-
32
- Square.sides #=> 4
11
+ class Polygon
12
+ class_attr_accessor :sides
13
+ end
14
+
15
+ Polygon.sides = 5
16
+ Polygon.sides #=> 5
17
+
18
+ class Square < Polygon
19
+ end
20
+
21
+ Square.sides #=> nil
22
+
23
+
24
+ class InheritablePolygon
25
+ inheritable_class_attr_accessor :sides
26
+ end
27
+
28
+ Polygon.sides = 4
29
+
30
+ class NewSquare < Polygon
31
+ end
32
+
33
+ Square.sides #=> 4
34
+ ```
33
35
 
34
36
  You can provide default values using a hash with :default set for the last value, or if just
35
37
  creating one accessor/reader/writer add `=> defaultvalue` to the end, this example should
36
38
  make it more clear:
37
39
 
38
- require 'attr_plus/class'
39
-
40
- class Person
41
- class_attr_accessor :name => 'John Doe'
42
- inheritable_class_attr_accessor :arms, :legs, :default => 2
43
- inheritable_class_attr_accessor :fingers, :toes, :default => 5
44
- end
45
-
46
- class Agent < Person
47
- @name = "James Bond"
48
- end
49
-
50
- Person.name #=> "John Doe"
51
- Person.arms #=> 2
52
- Person.toes #=> 5
53
- Agent.name #=> "James Bond"
54
- Agent.legs #=> 2
40
+ ``` ruby
41
+ require 'attr_plus/class'
42
+
43
+ class Person
44
+ class_attr_accessor :name => 'John Doe'
45
+ inheritable_class_attr_accessor :arms, :legs, :default => 2
46
+ inheritable_class_attr_accessor :fingers, :toes, :default => 5
47
+ end
48
+
49
+ class Agent < Person
50
+ @name = "James Bond"
51
+ end
52
+
53
+ Person.name #=> "John Doe"
54
+ Person.arms #=> 2
55
+ Person.toes #=> 5
56
+ Agent.name #=> "James Bond"
57
+ Agent.legs #=> 2
58
+ ```
55
59
 
56
60
 
57
61
  ## ModuleAttr
58
62
 
59
- Almost exactly the same as `class_*` but for modules. __Note__ there is no module inheritance
60
- so `inheritable_module_*` will not work, I am thinking of adding `includable_module_*` later
61
- but they aren't in yet so can't be used!
63
+ Almost exactly the same as `class_*` but for modules.
62
64
 
63
- require 'attr_plus/module'
65
+ ``` ruby
66
+ require 'attr_plus/module'
64
67
 
65
- module MyHouse
66
- module_attr_accessor :width, :height, :default => 200
67
- module_attr_accessor :rooms => []
68
- module_attr_accessor :number, :street, :city, :country
69
- end
70
-
71
- House.width = 500
72
- House.rooms = [:living_room, :kitchen]
73
- House.rooms.first #=> :living_room
68
+ module MyHouse
69
+ module_attr_accessor :width, :height, :default => 200
70
+ module_attr_accessor :rooms => []
71
+ module_attr_accessor :number, :street, :city, :country
72
+ end
73
+
74
+ House.width = 500
75
+ House.rooms = [:living_room, :kitchen]
76
+ House.rooms.first #=> :living_room
77
+ ```
74
78
 
75
79
 
76
80
  ## Instance Extensions
@@ -78,52 +82,106 @@ but they aren't in yet so can't be used!
78
82
  I've also added extensions to the methods for creating accessors on instances. These create
79
83
  private versions, working exactly the same in every other way.
80
84
 
81
- require 'attr_plus/instance'
82
-
83
- class SecretBox
84
- attr_writer :stuff
85
- private_attr_reader :stuff
86
-
87
- def initialize
88
- @stuff = []
89
- end
90
-
91
- def <<(val)
92
- stuff << val
93
- end
94
-
95
- def shake
96
- stuff[rand(stuff.size)]
97
- end
98
- end
99
-
100
- box = SecretBox.new
101
- box << "giraffe"
102
- box << "elephant"
103
- box << "camel"
104
- box << "cat"
105
- p box.shake #=> "giraffe"
106
- p box.stuff # NoMethodError: private method 'stuff' called
107
- box.stuff = %w(dog hamster fish)
108
- p box.shake #=> "fish"
85
+ ``` ruby
86
+ require 'attr_plus/instance'
87
+
88
+ class SecretBox
89
+ attr_writer :stuff
90
+ private_attr_reader :stuff
91
+
92
+ def initialize
93
+ @stuff = []
94
+ end
95
+
96
+ def <<(val)
97
+ stuff << val
98
+ end
99
+
100
+ def shake
101
+ stuff[rand(stuff.size)]
102
+ end
103
+ end
104
+
105
+ box = SecretBox.new
106
+ box << "giraffe"
107
+ box << "elephant"
108
+ box << "camel"
109
+ box << "cat"
110
+ p box.shake #=> "giraffe"
111
+ p box.stuff # NoMethodError: private method 'stuff' called
112
+ box.stuff = %w(dog hamster fish)
113
+ p box.shake #=> "fish"
114
+ ```
109
115
 
110
116
  And then as usual there are `private_attr_accessor` and `private_attr_writer` which work
111
117
  as expected.
112
118
 
113
119
 
120
+ ## HashAttr
121
+
122
+ You can now access specific keys of a hash using `hash_attr_*` or `class_hash_attr_*`. The
123
+ normal version will get the variable in an instance but the class version works at the class
124
+ level, for example,
125
+
126
+ ``` ruby
127
+ require_relative 'lib/attr_plus/hash'
128
+
129
+ class SomeApp
130
+ @config = {:name => 'SomeApp', :version => '3.1.7'}
131
+ class_hash_attr_accessor :@config, :name, :version
132
+
133
+ def self.config; @config; end
134
+ end
135
+
136
+ p SomeApp.config #=> {:name => 'SomeApp', :version => '3.1.7'}
137
+ SomeApp.name = 'CoolApp'
138
+ p SomeApp.name #=> 'CoolApp'
139
+ SomeApp.version = '4.0.0'
140
+ p SomeApp.config #=> {:name => 'CoolApp', :version => '4.0.0'}
141
+ ```
142
+
143
+ Uses the class versions, but it could easily be written using the normal versions (probably
144
+ the most usual way):
145
+
146
+ ``` ruby
147
+ class AnApp
148
+ def initialize
149
+ @config = {}
150
+ end
151
+
152
+ hash_attr_accessor :@config, :name, :version
153
+ attr_accessor :config
154
+ end
155
+
156
+ some_app = AnApp.new
157
+ some_app.name = 'AnotherApp'
158
+ some_app.version = '1.5.0'
159
+ p some_app.config #=> {:name => 'AnotherApp', :version => '1.5.0'}
160
+ ```
161
+
162
+ In both of these I've passed the instance variable as a symbol as the argument to get the hash
163
+ but I could have used just `:config` as I have create the methods in each. If the hash uses
164
+ string keys just pass the arguments to `.hash_attr_` as strings instead of symbols.
165
+
166
+
114
167
  ## Install
115
168
 
116
- (sudo) gem install attr_plus
169
+ ``` bash
170
+ $ (sudo) gem install attr_plus
171
+ ```
117
172
 
118
173
 
119
174
  ## Use
120
175
 
121
- require 'attr_plus'
122
-
123
- # or for specific methods
124
- require 'attr_plus/class' # for only class_*
125
- require 'attr_plus/module' # for only module_*
126
- require 'attr_plus/instance' # for only private_attr_*
176
+ ``` ruby
177
+ require 'attr_plus'
178
+
179
+ # OR for specific methods
180
+ require 'attr_plus/class' # for only class_*
181
+ require 'attr_plus/module' # for only module_*
182
+ require 'attr_plus/hash' # for only hash_*
183
+ require 'attr_plus/instance' # for only private_attr_*
184
+ ```
127
185
 
128
186
 
129
187
  ### Important!
@@ -1,3 +1,6 @@
1
+ $: << File.dirname(__FILE__)
2
+
1
3
  require 'attr_plus/class'
2
4
  require 'attr_plus/instance'
3
- require 'attr_plus/module'
5
+ require 'attr_plus/module'
6
+ require 'attr_plus/hash'
@@ -3,15 +3,15 @@ require 'attr_plus/ext'
3
3
  # Should add cattr_accessor, which provides accessors for @@ class
4
4
  # variables!
5
5
 
6
-
7
6
  class Class
8
7
 
9
8
  # Defines a method that allows you to read an instance variable set at the
10
9
  # class level. Also defines an _instance_ method that reads the same thing.
11
10
  # Comparable to #attr_reader for the class level.
12
11
  #
13
- # So in summary defines: .var (which gets @var) and
14
- # #var (which gets self.class.var)
12
+ # So in summary defines:
13
+ # - .var (which gets @var) and
14
+ # - #var (which gets self.class.var)
15
15
  #
16
16
  # @example
17
17
  #
@@ -41,7 +41,7 @@ class Class
41
41
  end
42
42
 
43
43
  def #{name}
44
- self.class.send(:#{name})
44
+ @#{name} ||= self.class.send(:#{name}).dup
45
45
  end
46
46
  EOS
47
47
  self.instance_variable_set("@#{name}", (default.dup rescue default))
@@ -75,6 +75,10 @@ class Class
75
75
  def self.#{name}=(obj)
76
76
  @#{name} = obj
77
77
  end
78
+
79
+ def #{name}=(obj)
80
+ @#{name} = obj
81
+ end
78
82
  EOS
79
83
  end
80
84
  end
@@ -101,6 +105,7 @@ class Class
101
105
  class_attr_writer(*names)
102
106
  end
103
107
 
108
+
104
109
  # Creates a class and instance method to read the class level variable(s)
105
110
  # with the name(s) provided. If no value has been set it attempts to use
106
111
  # the value of the superclass.
@@ -120,7 +125,7 @@ class Class
120
125
  end
121
126
 
122
127
  def #{name}
123
- self.class.send(:#{name})
128
+ @#{name} ||= self.class.send(:#{name})
124
129
  end
125
130
  EOS
126
131
  self.instance_variable_set("@#{name}", (default.dup rescue default))
@@ -0,0 +1,68 @@
1
+ class Module
2
+
3
+ # @param var [Symbol]
4
+ # Instance variable as a symbol, or method symbol to call which returns
5
+ # a hash.
6
+ #
7
+ # @param args [Symbol]
8
+ # Keys for +var+, these will have methods set up for retrieving them.
9
+ #
10
+ def hash_attr_reader(var, *args)
11
+ args.each do |arg|
12
+ self.class_eval <<-EOS
13
+ def #{arg}
14
+ #{var}[#{arg.inspect}]
15
+ end
16
+ EOS
17
+ end
18
+ end
19
+
20
+ # @param var [Symbol]
21
+ # Instance variable as a symbol, or method symbol to call which returns
22
+ # a hash.
23
+ #
24
+ # @param args [Symbol]
25
+ # Keys for +var+, these will have methods set up for writing to.
26
+ #
27
+ def hash_attr_writer(var, *args)
28
+ args.each do |arg|
29
+ self.class_eval <<-EOS
30
+ def #{arg}=(val)
31
+ #{var}[#{arg.inspect}] = val
32
+ end
33
+ EOS
34
+ end
35
+ end
36
+
37
+ def hash_attr_accessor(*args)
38
+ hash_attr_reader(*args)
39
+ hash_attr_writer(*args)
40
+ end
41
+
42
+ # Like #hash_attr_accessor but creates class methods
43
+ def class_hash_attr_accessor(*args)
44
+ class_hash_attr_reader(*args)
45
+ class_hash_attr_writer(*args)
46
+ end
47
+
48
+ def class_hash_attr_reader(var, *args)
49
+ args.each do |arg|
50
+ self.instance_eval <<-EOS
51
+ def #{arg}
52
+ #{var}[#{arg.inspect}]
53
+ end
54
+ EOS
55
+ end
56
+ end
57
+
58
+ def class_hash_attr_writer(var, *args)
59
+ args.each do |arg|
60
+ self.instance_eval <<-EOS
61
+ def #{arg}=(val)
62
+ #{var}[#{arg.inspect}] = val
63
+ end
64
+ EOS
65
+ end
66
+ end
67
+
68
+ end
@@ -0,0 +1,3 @@
1
+ module AttrPlus
2
+ VERSION = '0.4.1'
3
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe "Class" do
5
+
6
+
7
+ describe ".inheritable_class_attr_reader" do
8
+ subject { Class.new { inheritable_class_attr_reader :test } }
9
+
10
+ it "defines a read method for the class" do
11
+ subject.should respond_to :test
12
+ end
13
+
14
+ it "defines a read method for instances of the class" do
15
+ subject.new.should respond_to :test
16
+ end
17
+ end
18
+
19
+ describe ".inheritable_class_attr_writer" do
20
+ subject { Class.new { inheritable_class_attr_writer :test } }
21
+
22
+ it "defines a write method for the class" do
23
+ subject.should respond_to :test=
24
+ end
25
+
26
+ it "defines a write method for instances of the class" do
27
+ subject.new.should respond_to :test=
28
+ end
29
+ end
30
+
31
+ describe ".inheritable_class_attr_accessor" do
32
+ subject { Class.new { inheritable_class_attr_accessor :test } }
33
+
34
+ it "defines a read method for the class" do
35
+ subject.should respond_to :test
36
+ end
37
+
38
+ it "defines a write method for the class" do
39
+ subject.should respond_to :test=
40
+ end
41
+
42
+ it "defines a read method for instances of the class" do
43
+ subject.new.should respond_to :test
44
+ end
45
+
46
+ it "defines a write method for instances of the class" do
47
+ subject.new.should respond_to :test=
48
+ end
49
+ end
50
+
51
+ context "When there is a subclass of a class with inheritable_class_attrs" do
52
+
53
+ let(:sup) { Class.new { inheritable_class_attr_accessor :test } }
54
+ let(:sub) { Class.new(sup) }
55
+
56
+ it "has the methods of the superclass" do
57
+ sub.should respond_to :test
58
+ sub.should respond_to :test=
59
+ end
60
+
61
+ describe "calling the writer method on the subclass" do
62
+ it "should not alter the value on the superclass" do
63
+ sub.test = "changed"
64
+ sub.test.should == "changed"
65
+ sup.test.should_not == "changed"
66
+ end
67
+ end
68
+
69
+ describe "calling the writer method on the superclass" do
70
+ it "should alter the value on the subclass if not set" do
71
+ sup.test = "changed it"
72
+ sup.test.should == "changed it"
73
+ sub.test.should == "changed it"
74
+ end
75
+
76
+ it "should not alter the value on the subclass if set" do
77
+ sub.test = "already set"
78
+ sup.test = "change it"
79
+ sup.test.should == "change it"
80
+ sub.test.should == "already set"
81
+ end
82
+ end
83
+ end
84
+
85
+ context "When given a default value" do
86
+
87
+ subject { Class.new { class_attr_accessor :test => "hi" } }
88
+
89
+ it "returns the default value before it is changed" do
90
+ subject.test.should == "hi"
91
+ end
92
+
93
+ it "returns the new value if it is changed" do
94
+ subject.test = nil
95
+ subject.test.should be_nil
96
+ end
97
+
98
+ context "When this class is inherited" do
99
+ let(:sub) { Class.new(subject) }
100
+
101
+ it "returns the default value as well" do
102
+ sub.test.should == "hi"
103
+ end
104
+ end
105
+
106
+ end
107
+
108
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Class do
3
+ describe "Class" do
4
4
 
5
5
  describe ".class_attr_reader" do
6
6
  subject { Class.new { class_attr_reader :test } }
@@ -20,6 +20,10 @@ describe Class do
20
20
  it "defines a write method for the class" do
21
21
  subject.should respond_to :test=
22
22
  end
23
+
24
+ it "defines a write method for instances of the class" do
25
+ subject.new.should respond_to :test=
26
+ end
23
27
  end
24
28
 
25
29
  describe ".class_attr_accessor" do
@@ -36,8 +40,15 @@ describe Class do
36
40
  it "defines a read method for instances of the class" do
37
41
  subject.new.should respond_to :test
38
42
  end
43
+
44
+ it "defines a write method for instances of the class" do
45
+ subject.new.should respond_to :test=
46
+ end
39
47
  end
40
48
 
49
+
50
+ # EDGE CASES, specifically where I've had issues in the past so need to check against
51
+
41
52
  # The subclass thing was starting to annoy me...
42
53
  context "When there is a subclass of a class with class_attrs" do
43
54
 
@@ -65,108 +76,38 @@ describe Class do
65
76
  end
66
77
  end
67
78
  end
68
-
69
-
70
- # Inheritable class attributes
71
-
72
- describe ".inheritable_class_attr_reader" do
73
- subject { Class.new { inheritable_class_attr_reader :test } }
74
-
75
- it "defines a read method for the class" do
76
- subject.should respond_to :test
77
- end
78
-
79
- it "defines a read method for instances of the class" do
80
- subject.new.should respond_to :test
81
- end
82
- end
83
79
 
84
- describe ".inheritable_class_attr_writer" do
85
- subject { Class.new { inheritable_class_attr_writer :test } }
86
-
87
- it "defines a write method for the class" do
88
- subject.should respond_to :test=
89
- end
90
- end
91
-
92
- describe ".inheritable_class_attr_accessor" do
93
- subject { Class.new { inheritable_class_attr_accessor :test } }
94
80
 
95
- it "defines a read method for the class" do
96
- subject.should respond_to :test
97
- end
98
-
99
- it "defines a write method for the class" do
100
- subject.should respond_to :test=
101
- end
102
-
103
- it "defines a read method for instances of the class" do
104
- subject.new.should respond_to :test
105
- end
106
- end
81
+ context "When there are multiple instances of a class with class_attrs" do
107
82
 
108
- context "When there is a subclass of a class with inheritable_class_attrs" do
83
+ subject { Class.new { class_attr_accessor :attrs } }
84
+ let(:obj1) { subject.new }
85
+ let(:obj2) { subject.new }
109
86
 
110
- let(:sup) { Class.new { inheritable_class_attr_accessor :test } }
111
- let(:sub) { Class.new(sup) }
112
-
113
- it "has the methods of the superclass" do
114
- sub.should respond_to :test
115
- sub.should respond_to :test=
116
- end
117
-
118
- describe "calling the writer method on the subclass" do
119
- it "should not alter the value on the superclass" do
120
- sub.test = "changed"
121
- sub.test.should == "changed"
122
- sup.test.should_not == "changed"
123
- end
124
- end
125
-
126
- describe "calling the writer method on the superclass" do
127
- it "should alter the value on the subclass if not set" do
128
- sup.test = "changed it"
129
- sup.test.should == "changed it"
130
- sub.test.should == "changed it"
87
+ describe "the class" do
88
+ it "should not be affected by changes to the objects" do
89
+ subject.attrs = %w(coolness)
90
+ obj1.attrs = %w(height weight)
91
+ obj2.attrs = %w(volume density)
92
+ subject.attrs.should == %w(coolness)
131
93
  end
132
94
 
133
- it "should not alter the value on the subclass if set" do
134
- sub.test = "already set"
135
- sup.test = "change it"
136
- sup.test.should == "change it"
137
- sub.test.should == "already set"
95
+ it "should not affect objects when they have been changed" do
96
+ obj1.attrs = %w(name)
97
+ obj2.attrs = %w(date)
98
+ subject.attrs = %w(mass)
99
+ obj1.attrs.should == %w(name)
100
+ obj2.attrs.should == %w(date)
138
101
  end
139
- end
140
- end
141
-
142
- context "When given a default value" do
143
-
144
- subject { Class.new { class_attr_accessor :test => "hi" } }
145
-
146
- it "returns the default value before it is changed" do
147
- subject.test.should == "hi"
148
- end
149
-
150
- it "returns the new value if it is changed" do
151
- subject.test = nil
152
- subject.test.should be_nil
153
- end
154
-
155
- context "When this class is inherited" do
156
- let(:sub) { Class.new(subject) }
157
102
 
158
- it "returns the default value as well" do
159
- sub.test.should == "hi"
103
+ it "should affect objects when they have not been changed" do
104
+ obj1.attrs = %w(hp)
105
+ subject.attrs = %w(mp)
106
+ obj1.attrs.should == %w(hp)
107
+ obj2.attrs.should == %w(mp)
160
108
  end
161
109
  end
162
-
163
- end
164
-
165
-
166
- # Class Variables
167
-
168
- describe ".cattr_accessor" do
169
110
 
170
111
  end
171
-
112
+
172
113
  end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Hash" do
4
+
5
+ describe '.hash_attr_reader' do
6
+ subject {
7
+ Class.new {
8
+ hash_attr_reader :@config, :name
9
+ def initialize
10
+ @config = {:name => "John Doe"}
11
+ end
12
+ }.new
13
+ }
14
+
15
+ it "creates the reader method" do
16
+ subject.should respond_to :name
17
+ end
18
+
19
+ it "gets the value from the correct hash" do
20
+ subject.name.should == "John Doe"
21
+ end
22
+ end
23
+
24
+ describe '.hash_attr_writer' do
25
+ subject {
26
+ Class.new {
27
+ attr_reader :config
28
+ hash_attr_writer :@config, :name
29
+ def initialize
30
+ @config = {}
31
+ end
32
+ }.new
33
+ }
34
+
35
+ it "creates the writer method" do
36
+ subject.should respond_to :name=
37
+ end
38
+
39
+ it "sets the value in the hash" do
40
+ subject.name = "John Doe"
41
+ subject.config[:name].should == "John Doe"
42
+ end
43
+ end
44
+
45
+
46
+ describe '.hash_attr_accessor' do
47
+ subject {
48
+ Class.new {
49
+ attr_reader :config
50
+ hash_attr_accessor :@config, :name, :age
51
+ def initialize
52
+ @config = {
53
+ :name => 'John Doe',
54
+ :age => 21
55
+ }
56
+ end
57
+ }.new
58
+ }
59
+
60
+ it "creates the methods" do
61
+ subject.should respond_to :name
62
+ subject.should respond_to :age
63
+ subject.should respond_to :name=
64
+ subject.should respond_to :age=
65
+ end
66
+
67
+ it "allows you to read values" do
68
+ subject.name.should == 'John Doe'
69
+ subject.age.should == 21
70
+ end
71
+
72
+ it "allows you to set values" do
73
+ subject.name = 'Dave Jones'
74
+ subject.age = 59
75
+ subject.config.should == {:name => 'Dave Jones', :age => 59}
76
+ end
77
+ end
78
+
79
+
80
+ describe '.class_hash_attr_reader' do
81
+ subject {
82
+ Class.new {
83
+ @config = {:name => 'John Doe'}
84
+ class_hash_attr_reader :@config, :name
85
+ }
86
+ }
87
+
88
+ it "creates the reader method" do
89
+ subject.should respond_to :name
90
+ end
91
+
92
+ it "gets the value from the correct hash" do
93
+ subject.name.should == "John Doe"
94
+ end
95
+ end
96
+
97
+ describe '.class_hash_attr_writer' do
98
+ subject {
99
+ Class.new {
100
+ @config = {}
101
+ class_hash_attr_writer :@config, :name
102
+ class << self; attr_accessor :config; end
103
+ }
104
+ }
105
+
106
+ it "creates the writer method" do
107
+ subject.should respond_to :name=
108
+ end
109
+
110
+ it "sets the value in the hash" do
111
+ subject.name = "John Doe"
112
+ subject.config[:name].should == "John Doe"
113
+ end
114
+ end
115
+
116
+ describe '.hash_attr_accessor' do
117
+ subject {
118
+ Class.new {
119
+ class << self; attr_reader :config; end
120
+ class_hash_attr_accessor :@config, :name, :age
121
+ @config = {
122
+ :name => 'John Doe',
123
+ :age => 21
124
+ }
125
+ }
126
+ }
127
+
128
+ it "creates the methods" do
129
+ subject.should respond_to :name
130
+ subject.should respond_to :age
131
+ subject.should respond_to :name=
132
+ subject.should respond_to :age=
133
+ end
134
+
135
+ it "allows you to read values" do
136
+ subject.name.should == 'John Doe'
137
+ subject.age.should == 21
138
+ end
139
+
140
+ it "allows you to set values" do
141
+ subject.name = 'Dave Jones'
142
+ subject.age = 59
143
+ subject.config.should == {:name => 'Dave Jones', :age => 59}
144
+ end
145
+ end
146
+
147
+ context 'When using string keys' do
148
+ subject {
149
+ Class.new {
150
+ hash_attr_accessor :@config, 'name'
151
+ def initialize
152
+ @config = {'name' => "John Doe"}
153
+ end
154
+ }.new
155
+ }
156
+
157
+ it "allows access to values" do
158
+ subject.name.should == 'John Doe'
159
+ end
160
+
161
+ it "allows values to be set" do
162
+ subject.name = 'Tom'
163
+ subject.name.should == 'Tom'
164
+ end
165
+ end
166
+
167
+ end
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Module do
3
+ describe "Instance" do
4
4
 
5
5
  describe ".private_attr_reader" do
6
6
  subject {
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Module do
3
+ describe "Module" do
4
4
 
5
5
  describe "#module_attr_reader" do
6
6
  subject { Module.new { module_attr_reader :test } }
@@ -38,18 +38,9 @@ describe Module do
38
38
  end
39
39
 
40
40
  it "returns the new value if it is changed" do
41
- subject.test = nil
42
- subject.test.should be_nil
43
- end
44
-
45
- context "when this module is included" do
46
- subject { Class.new { include Module.new { module_attr_accessor :test => "hi" } } }
47
-
48
- it "returns the default value as well" do
49
- subject.test.should == "hi"
50
- end
51
- end
52
-
41
+ subject.test = "bye"
42
+ subject.test.should == "bye"
43
+ end
53
44
  end
54
45
 
55
46
  end
@@ -1,11 +1,13 @@
1
1
  if RUBY_VERSION >= "1.9"
2
2
  require 'duvet'
3
- Duvet.start :filter => 'class_attr/lib'
3
+ Duvet.start :filter => 'attr_plus/lib'
4
4
  end
5
5
 
6
6
  require 'rspec'
7
7
  require 'attr_plus'
8
8
 
9
- RSpec.configure do |config|
10
- config.color_enabled = true
11
- end
9
+ RSpec.configure do |c|
10
+ c.color_enabled = true
11
+ c.filter_run :focus => true
12
+ c.run_all_when_everything_filtered = true
13
+ end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Using a class level instance hash to hold config" do
4
+
5
+ subject {
6
+ Class.new {
7
+ @config = {:name => 'SomeApp', :version => '3.1.7'}
8
+ def self.config; @config; end
9
+ class_hash_attr_accessor :config, :name, :version
10
+ }
11
+ }
12
+
13
+ it "should get the values" do
14
+ subject.config.should == {:name => 'SomeApp', :version => '3.1.7'}
15
+ subject.name.should == 'SomeApp'
16
+ subject.version.should == '3.1.7'
17
+ end
18
+
19
+ end
20
+
21
+ describe "Using an instance level hash to hold config" do
22
+
23
+ subject {
24
+ Class.new {
25
+ def initialize; @config = {}; end
26
+ attr_accessor :config
27
+ hash_attr_accessor :config, :name, :version
28
+ }.new
29
+ }
30
+
31
+ it "should get the values" do
32
+ subject.name = 'SomeApp'
33
+ subject.version = '1.5.0'
34
+ subject.config.should == {:name => 'SomeApp', :version => '1.5.0'}
35
+ end
36
+
37
+ end
38
+
39
+
40
+ describe "Putting things in a box" do
41
+
42
+ subject {
43
+ Class.new {
44
+ attr_writer :stuff
45
+ private_attr_reader :stuff
46
+
47
+ def initialize
48
+ @stuff = []
49
+ end
50
+
51
+ def <<(val)
52
+ stuff << val
53
+ end
54
+
55
+ def shake
56
+ stuff[rand(stuff.size)]
57
+ end
58
+ }.new
59
+ }
60
+
61
+ it "should work" do
62
+ subject << "giraffe"
63
+ subject << "elephant"
64
+ subject << "camel"
65
+ subject << "cat"
66
+ %w(giraffe elephant camel cat).should include subject.shake
67
+ expect { subject.stuff }.to raise_error NoMethodError
68
+ subject.stuff = %w(dog hamster fish)
69
+ %w(dog hamster fish).should include subject.shake
70
+ end
71
+
72
+ end
73
+
74
+
75
+ describe "Storing lists of attributes for a class" do
76
+
77
+ before {
78
+ @file = Class.new {
79
+ inheritable_class_attr_accessor :keys => []
80
+ def self.attr(*attrs)
81
+ keys.concat attrs
82
+ end
83
+ attr :url, :permalink, :path, :content
84
+ }
85
+
86
+ @page = Class.new(@file) { attr :title }
87
+ @post = Class.new(@page) { attr :date, :tags }
88
+ }
89
+
90
+ it "should work" do
91
+ @file.keys.should == [:url, :permalink, :path, :content]
92
+ @page.keys.should == [:url, :permalink, :path, :content, :title]
93
+ @post.keys.should == [:url, :permalink, :path, :content, :title, :date, :tags]
94
+ end
95
+ end
96
+
97
+
98
+ describe "A set of polygons" do
99
+
100
+ before {
101
+ @polygon = Class.new {
102
+ class_attr_writer :sides
103
+ def self.triangle?; @sides == 3; end
104
+ def self.rectangle?; @sides == 4; end
105
+ def self.pentagon?; @sides == 5; end
106
+ def self.nothing?; @sides.nil?; end
107
+ }
108
+
109
+ @triangle = Class.new(@polygon) { @sides = 3 }
110
+ @rectangle = Class.new(@polygon) { @sides = 4 }
111
+ @pentagon = Class.new(@polygon) { @sides = 5 }
112
+ }
113
+
114
+ it "should work" do
115
+ @triangle.should be_a_triangle
116
+ @rectangle.should be_a_rectangle
117
+ @pentagon.should be_a_pentagon
118
+ @polygon.should be_nothing
119
+ end
120
+
121
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attr_plus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-04-27 00:00:00.000000000 +01:00
12
+ date: 2011-06-08 00:00:00.000000000 +01:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
  description: ! " Provides attr_accessor style methods for easily creating methods
@@ -24,15 +24,20 @@ files:
24
24
  - LICENSE
25
25
  - lib/attr_plus/class.rb
26
26
  - lib/attr_plus/ext.rb
27
+ - lib/attr_plus/hash.rb
27
28
  - lib/attr_plus/instance.rb
28
29
  - lib/attr_plus/module.rb
30
+ - lib/attr_plus/version.rb
29
31
  - lib/attr_plus.rb
30
32
  - lib/class_attr.rb
33
+ - spec/attr_plus/class_inheirtable_spec.rb
31
34
  - spec/attr_plus/class_spec.rb
35
+ - spec/attr_plus/hash_spec.rb
32
36
  - spec/attr_plus/instance_spec.rb
33
37
  - spec/attr_plus/module_spec.rb
34
- - spec/class_attr_spec.rb
38
+ - spec/attr_plus_spec.rb
35
39
  - spec/spec_helper.rb
40
+ - spec/usage_spec.rb
36
41
  has_rdoc: false
37
42
  homepage: http://github.com/hawx/attr_plus
38
43
  licenses: []
@@ -59,8 +64,11 @@ signing_key:
59
64
  specification_version: 3
60
65
  summary: attr_accessor for class and module level instance variables.
61
66
  test_files:
67
+ - spec/attr_plus/class_inheirtable_spec.rb
62
68
  - spec/attr_plus/class_spec.rb
69
+ - spec/attr_plus/hash_spec.rb
63
70
  - spec/attr_plus/instance_spec.rb
64
71
  - spec/attr_plus/module_spec.rb
65
- - spec/class_attr_spec.rb
72
+ - spec/attr_plus_spec.rb
66
73
  - spec/spec_helper.rb
74
+ - spec/usage_spec.rb