cascading_classes 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +41 -18
- data/lib/cascading_classes/cascading_classes.rb +28 -142
- data/lib/cascading_classes/dsl.rb +83 -0
- data/lib/cascading_classes.rb +48 -37
- data/spec/extended_spec.rb +40 -6
- data/spec/helper_spec.rb +7 -0
- data/spec/included_spec.rb +12 -0
- data/spec/note.txt +2 -0
- metadata +9 -3
data/README.md
CHANGED
@@ -100,17 +100,16 @@ is equivalent to
|
|
100
100
|
hair_color :default => "blond"
|
101
101
|
end
|
102
102
|
|
103
|
-
or
|
103
|
+
or
|
104
104
|
|
105
105
|
Parent.all! do
|
106
106
|
eye_color :initial => "blue"
|
107
107
|
hair_color :initial => "blond"
|
108
108
|
end
|
109
109
|
|
110
|
-
|
110
|
+
### More block examples
|
111
111
|
|
112
112
|
The folowing are all equivalent
|
113
|
-
==============================
|
114
113
|
|
115
114
|
Parent.cascade :address, :phone, [:email, "jon@example.com"]
|
116
115
|
|
@@ -137,44 +136,69 @@ You can also set a property in a block using ```set_property```
|
|
137
136
|
|
138
137
|
## Quick Summary
|
139
138
|
|
140
|
-
|
141
|
-
|
139
|
+
Note: CC is equivalent to CascadingClasses
|
140
|
+
|
141
|
+
require the gem
|
142
|
+
|
143
|
+
require cascading_classes
|
144
|
+
|
145
|
+
extend or include the module
|
146
|
+
|
142
147
|
class Foo
|
143
148
|
extend CascadingClasses
|
144
149
|
end
|
145
|
-
|
146
|
-
|
150
|
+
|
151
|
+
create some cascading properties by listing them
|
152
|
+
|
147
153
|
A.cascade :desk, :chair, :lamp
|
148
|
-
|
154
|
+
|
155
|
+
or by using a block
|
156
|
+
|
157
|
+
A.cascade do
|
158
|
+
desk
|
159
|
+
chair
|
160
|
+
lamp
|
161
|
+
end
|
162
|
+
|
163
|
+
or
|
164
|
+
|
149
165
|
A.cascade{ desk; chair; lamp }
|
150
|
-
|
166
|
+
|
167
|
+
get and set the property on any descendent
|
168
|
+
|
151
169
|
class B < A; end
|
170
|
+
|
152
171
|
B.desk = "a large, wooden structure in need of a fix"
|
172
|
+
|
153
173
|
class C < A; end
|
174
|
+
|
154
175
|
C.lamp = "old and rusty"
|
155
176
|
|
156
|
-
|
177
|
+
## What's the difference between ```extend CC``` and ```include CC```?
|
178
|
+
|
179
|
+
First, in either case you are dealing with class instance variables and class methods.
|
157
180
|
|
158
|
-
|
181
|
+
A.cascade :eye_color
|
182
|
+
A.eye_color = "blue"
|
159
183
|
|
160
|
-
|
184
|
+
sets ```@eye_color``` on the singleton class of ```A```.
|
161
185
|
|
162
|
-
|
186
|
+
But if you also want the properties to cascade to instance variables, you have three options. The first is to ```include CC```, which, by default, creates the properties on instances too
|
163
187
|
|
164
188
|
class Parent
|
165
189
|
include CC
|
166
190
|
end
|
167
191
|
|
168
|
-
Parent.cascade [:
|
192
|
+
Parent.cascade [:one, 1]
|
169
193
|
p = Parent.new
|
170
|
-
p p.
|
194
|
+
p p.one # => 1
|
171
195
|
|
172
196
|
class Child < Parent; end
|
173
197
|
|
174
198
|
c = Child.new
|
175
|
-
p c.
|
199
|
+
p c.one # => 1
|
176
200
|
|
177
|
-
The other two ways to
|
201
|
+
The other two ways to ensure instances have cascaded properties is by including a third argument
|
178
202
|
|
179
203
|
Parent.cascade [:hair_color, "blue", true]
|
180
204
|
|
@@ -187,4 +211,3 @@ or
|
|
187
211
|
In either case, even if you ```extend CC```, all instance variables of all descendents will have the ```hair_color``` property.
|
188
212
|
|
189
213
|
|
190
|
-
|
@@ -1,163 +1,49 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# based off
|
4
|
-
# http://blog.oleganza.com/post/115377756/correct-blankslate-in-ruby
|
5
|
-
class BlankSlate
|
6
|
-
class << self; alias __undef_method undef_method; end
|
7
|
-
keep = [:instance_eval, :object_id]
|
8
|
-
ancestors.inject([]){|res, a| res + (a.instance_methods - keep)}.uniq.
|
9
|
-
each{|m| (__undef_method(m) rescue nil) unless m =~ /^__/ }
|
10
|
-
end
|
1
|
+
require 'cascading_classes/dsl'
|
11
2
|
|
12
|
-
|
13
|
-
|
14
|
-
def method_missing(meth, *args, &block)
|
15
|
-
case meth
|
16
|
-
when /inspect/
|
17
|
-
super
|
18
|
-
when /set_property/
|
19
|
-
__property__(args[0], *args[1..-1], &block)
|
20
|
-
else
|
21
|
-
__property__(meth, *args, &block)
|
22
|
-
end
|
23
|
-
end
|
3
|
+
module CascadingClasses
|
24
4
|
|
25
|
-
|
26
|
-
|
5
|
+
def self.cascade_intern(klass, property)
|
6
|
+
Module.new do
|
27
7
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
args[:start]
|
34
|
-
elsif args.include? :begin
|
35
|
-
args[:begin]
|
36
|
-
else
|
37
|
-
nil
|
8
|
+
define_method property do
|
9
|
+
val = instance_variable_get "@#{property}"
|
10
|
+
return val unless (val.nil? and self != klass)
|
11
|
+
(self.class == Class) ? superclass.send(property) :
|
12
|
+
self.class.send(property)
|
38
13
|
end
|
39
14
|
|
40
|
-
|
41
|
-
|
42
|
-
elsif args.include? :only_classes
|
43
|
-
!args[:only_classes]
|
44
|
-
elsif args.include? :classes_only
|
45
|
-
!args[:classes_only]
|
46
|
-
elsif args.include? :exclude_instances
|
47
|
-
!args[:exclude_instances]
|
48
|
-
elsif args.include? :skip_instances
|
49
|
-
!args[:skip_instances]
|
50
|
-
elsif args.include? :not_instances
|
51
|
-
!args[:not_instances]
|
52
|
-
elsif args.include? :apply_to_instances
|
53
|
-
args[:apply_to_instances]
|
54
|
-
elsif args.include? :both
|
55
|
-
args[:both]
|
56
|
-
elsif args.include? :instances_too
|
57
|
-
args[:instances_too]
|
58
|
-
elsif args.include? :instances
|
59
|
-
args[:instances]
|
60
|
-
elsif args.include? :instance
|
61
|
-
args[:instance]
|
62
|
-
else
|
63
|
-
@apply_to_instances
|
15
|
+
define_method "#{property}=" do |v|
|
16
|
+
instance_variable_set "@#{property}", v
|
64
17
|
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def initialize(apply_to_instances, &block)
|
68
|
-
@apply_to_instances = apply_to_instances
|
69
|
-
@names = []
|
70
|
-
@defaults = {}
|
71
|
-
@instances_too = {} # values are true/false
|
72
18
|
|
73
|
-
return unless block_given?
|
74
|
-
if block.arity == 0
|
75
|
-
instance_eval &block
|
76
|
-
else
|
77
|
-
raise "ArgumentError: wrong number of args for block: #{block.arity} for 1"
|
78
|
-
end
|
79
19
|
end
|
20
|
+
end
|
80
21
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
# apply_to_instances: whether properties should be set on instances of the classes too
|
85
|
-
def self.cascading_props(apply_to_instances, *properties, &block)
|
86
|
-
props = {} # values are defaults
|
87
|
-
instances_too = {} # values are true/false
|
22
|
+
# returns hash: {..., attr => [default, inst_too], .. }
|
23
|
+
def self.parse_options(klass, apply_to_instances, *properties, &block)
|
24
|
+
res = {}
|
88
25
|
properties.each do |prop|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
26
|
+
name, default, inst_too = prop, nil, apply_to_instances
|
27
|
+
if Array === prop
|
28
|
+
case prop.size
|
29
|
+
when 0 then next
|
30
|
+
when 1 then name = prop[0]
|
31
|
+
when 2 then name, default = prop[0..1]
|
32
|
+
else name, default, inst_too = prop[0..2]
|
33
|
+
end
|
96
34
|
end
|
35
|
+
inst_too = !!inst_too
|
36
|
+
res[name.to_sym] = [default, inst_too]
|
97
37
|
end
|
98
|
-
|
99
|
-
props.each{|prop, default| instances_too[prop] =
|
100
|
-
apply_to_instances unless instances_too.include? prop}
|
101
38
|
|
102
39
|
if block_given?
|
103
|
-
a =
|
40
|
+
a = CascadingClasses::DSL.new(apply_to_instances, &block)
|
104
41
|
names, defaults, inst =
|
105
42
|
a.instance_eval{ [@names, @defaults, @instances_too] }
|
106
|
-
names.each
|
107
|
-
props[prop] = defaults[prop]
|
108
|
-
instances_too[prop] = inst[prop]
|
109
|
-
end
|
43
|
+
names.each{|name| res[name] = [defaults[name], inst[name]] }
|
110
44
|
end
|
111
45
|
|
112
|
-
|
113
|
-
mod = Module.new do
|
114
|
-
|
115
|
-
define_method :extended do |klass|
|
116
|
-
klass.class_eval{ instance_variable_set "@#{prop}", default }
|
117
|
-
end
|
118
|
-
module_function :extended
|
119
|
-
|
120
|
-
define_method :included do |klass|
|
121
|
-
klass.class_eval{ instance_variable_set "@#{prop}", default }
|
122
|
-
end
|
123
|
-
module_function :included
|
124
|
-
|
125
|
-
# getter has dual role as setter:
|
126
|
-
# m.prop val <=> m.prop = val
|
127
|
-
define_method prop do |*args|
|
128
|
-
if args.empty? # getter
|
129
|
-
val = instance_variable_get "@#{prop}"
|
130
|
-
if val.nil?
|
131
|
-
# reach up into the class first, then into superclass
|
132
|
-
if self.class == Class
|
133
|
-
try_super = superclass.instance_eval{ respond_to? "#{prop}" }
|
134
|
-
return superclass.send("#{prop}") if try_super
|
135
|
-
else
|
136
|
-
try_klass_methd = self.class.send :respond_to?, prop
|
137
|
-
return self.class.send(prop) if try_klass_methd
|
138
|
-
end
|
139
|
-
end
|
140
|
-
val
|
141
|
-
else # setter
|
142
|
-
if args.size == 1 and Array === args[0]
|
143
|
-
send("#{prop}=", args[0])
|
144
|
-
else
|
145
|
-
send("#{prop}=", *args)
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
# todo: setter validations ??
|
151
|
-
define_method "#{prop}=" do |*vals|
|
152
|
-
if vals.size == 1 and Array === vals[0]
|
153
|
-
vals = vals[0]
|
154
|
-
end
|
155
|
-
instance_variable_set "@#{prop}", vals[0]
|
156
|
-
end
|
157
|
-
|
158
|
-
end # new module
|
159
|
-
[prop, props[prop], instances_too[prop], mod]
|
160
|
-
end
|
46
|
+
res
|
161
47
|
end
|
162
48
|
|
163
49
|
end # module CascadingClasses
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module CascadingClasses
|
2
|
+
|
3
|
+
# based off
|
4
|
+
# http://blog.oleganza.com/post/115377756/correct-blankslate-in-ruby
|
5
|
+
class BlankSlate
|
6
|
+
class << self; alias __undef_method undef_method; end
|
7
|
+
keep = [:instance_eval, :object_id]
|
8
|
+
ancestors.inject([]){|res, a| res + (a.instance_methods - keep)}.uniq.
|
9
|
+
each{|m| (__undef_method(m) rescue nil) unless m =~ /^__/ }
|
10
|
+
end
|
11
|
+
|
12
|
+
class DSL < BlankSlate
|
13
|
+
|
14
|
+
def method_missing(meth, *args, &block)
|
15
|
+
case meth
|
16
|
+
when /inspect/
|
17
|
+
super
|
18
|
+
when /set_property/
|
19
|
+
__property__(args[0], *args[1..-1], &block)
|
20
|
+
else
|
21
|
+
__property__(meth, *args, &block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def __property__(name, args={}, &block)
|
26
|
+
@names << name unless @names.include? name
|
27
|
+
|
28
|
+
@defaults[name] = if args.include? :default
|
29
|
+
args[:default]
|
30
|
+
elsif args.include? :initial
|
31
|
+
args[:initial]
|
32
|
+
elsif args.include? :start
|
33
|
+
args[:start]
|
34
|
+
elsif args.include? :begin
|
35
|
+
args[:begin]
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
|
40
|
+
@instances_too[name] = if args.include? :classes_only
|
41
|
+
!args[:classes_only]
|
42
|
+
elsif args.include? :only_classes
|
43
|
+
!args[:only_classes]
|
44
|
+
elsif args.include? :classes_only
|
45
|
+
!args[:classes_only]
|
46
|
+
elsif args.include? :exclude_instances
|
47
|
+
!args[:exclude_instances]
|
48
|
+
elsif args.include? :skip_instances
|
49
|
+
!args[:skip_instances]
|
50
|
+
elsif args.include? :not_instances
|
51
|
+
!args[:not_instances]
|
52
|
+
elsif args.include? :apply_to_instances
|
53
|
+
args[:apply_to_instances]
|
54
|
+
elsif args.include? :both
|
55
|
+
args[:both]
|
56
|
+
elsif args.include? :instances_too
|
57
|
+
args[:instances_too]
|
58
|
+
elsif args.include? :instances
|
59
|
+
args[:instances]
|
60
|
+
elsif args.include? :instance
|
61
|
+
args[:instance]
|
62
|
+
else
|
63
|
+
@apply_to_instances
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize(apply_to_instances, &block)
|
68
|
+
@apply_to_instances = apply_to_instances
|
69
|
+
@names = []
|
70
|
+
@defaults = {}
|
71
|
+
@instances_too = {} # values are true/false
|
72
|
+
|
73
|
+
return unless block_given?
|
74
|
+
if block.arity == 0
|
75
|
+
instance_eval &block
|
76
|
+
else
|
77
|
+
raise "ArgumentError: wrong number of args for block: #{block.arity} for 1"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
end # class Helper
|
82
|
+
|
83
|
+
end # module CascadingClasses
|
data/lib/cascading_classes.rb
CHANGED
@@ -11,17 +11,17 @@ CC = CascadingClasses unless defined? CC
|
|
11
11
|
# cascade :one, :two, :three, ...
|
12
12
|
# end
|
13
13
|
# Foo.one = 12
|
14
|
-
# Foo.new.one
|
15
|
-
# Bar = Class.new(Foo).one
|
14
|
+
# Foo.new.one # => 12
|
15
|
+
# Bar = Class.new(Foo).one # => 12
|
16
|
+
# Bar.new.one # => 12
|
16
17
|
|
17
18
|
module CascadingClasses
|
18
19
|
|
19
|
-
# VERSION: "1.0.0"
|
20
20
|
# note, VERSION will be undetected unless called directly
|
21
21
|
def self.const_missing(name)
|
22
22
|
case name
|
23
|
-
when :VERSION then "
|
24
|
-
else
|
23
|
+
when :VERSION then "0.2.0"
|
24
|
+
else super
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -30,46 +30,57 @@ module CascadingClasses
|
|
30
30
|
end
|
31
31
|
module_function :respond_to?
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
# todo: fill in rest
|
34
|
+
# todo: allow one of [:cascade, :all!] to be overwritten
|
35
|
+
def self.illegal_names
|
36
|
+
[:cascade, :all!, :instance_eval, :instance_exec, :class_eval]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.apply(klass, instances_too)
|
40
|
+
klass.singleton_class.instance_eval do
|
41
|
+
|
42
|
+
define_method :cascade do |*props, &block|
|
43
|
+
illegal_names = CascadingClasses.illegal_names
|
44
|
+
|
45
|
+
props = CascadingClasses.parse_options(klass, instances_too, *props, &block)
|
46
|
+
props.each{|prop, v| raise NameError, "Illegal property name: #{prop}" if
|
47
|
+
illegal_names.include? prop }
|
48
|
+
|
49
|
+
props.each do |prop, v|
|
50
|
+
default, inst_too = v
|
51
|
+
|
52
|
+
klass.singleton_class.instance_eval do
|
53
|
+
undef_method prop.to_sym rescue nil
|
54
|
+
undef_method "#{prop}=".to_sym rescue nil
|
55
|
+
end
|
56
|
+
|
57
|
+
klass.instance_eval{ instance_variable_set "@#{prop}", default }
|
58
|
+
|
59
|
+
mod = CascadingClasses.cascade_intern(klass, prop)
|
60
|
+
klass.extend mod
|
61
|
+
if inst_too
|
62
|
+
klass.instance_eval do
|
63
|
+
undef_method prop.to_sym rescue nil
|
64
|
+
undef_method "#{prop}=".to_sym rescue nil
|
65
|
+
end
|
66
|
+
klass.send(:include, mod)
|
67
|
+
end
|
42
68
|
end
|
43
|
-
{self.name => Hash[res]}
|
44
69
|
end
|
45
70
|
|
46
|
-
|
47
|
-
|
48
|
-
alias_method :all!, :cascade
|
49
|
-
end
|
71
|
+
unless instance_methods.include? :all!
|
72
|
+
alias_method :all!, :cascade
|
50
73
|
end
|
74
|
+
|
51
75
|
end
|
52
76
|
end
|
53
77
|
|
54
|
-
def self.
|
55
|
-
|
56
|
-
|
57
|
-
def cascade(*props, &block)
|
58
|
-
res = CascadingClasses.cascading_props(false, *props, &block)
|
59
|
-
res.map! do |prop, default, apply_to_instances, mod|
|
60
|
-
send(:extend, mod)
|
61
|
-
send(:include, mod) if apply_to_instances
|
62
|
-
[prop, [default, apply_to_instances]]
|
63
|
-
end
|
64
|
-
{self.name => Hash[res]}
|
65
|
-
end
|
78
|
+
def self.included(klass)
|
79
|
+
apply(klass, true)
|
80
|
+
end
|
66
81
|
|
67
|
-
|
68
|
-
|
69
|
-
alias_method :all!, :cascade
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
82
|
+
def self.extended(klass)
|
83
|
+
apply(klass, false)
|
73
84
|
end
|
74
85
|
|
75
86
|
end # module CascadingClases
|
data/spec/extended_spec.rb
CHANGED
@@ -27,6 +27,16 @@ describe "when a class extends CascadingClasses" do
|
|
27
27
|
GrandChild = Class.new(Child)
|
28
28
|
end
|
29
29
|
|
30
|
+
describe "when a parent has a default" do
|
31
|
+
before do
|
32
|
+
Parent.cascade [:eyes, "brown"]
|
33
|
+
end
|
34
|
+
|
35
|
+
it "sets the property to the default" do
|
36
|
+
Parent.eyes.must_equal "brown"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
30
40
|
describe "when a property is set from above" do
|
31
41
|
before do
|
32
42
|
Parent.cascade(:hair_color)
|
@@ -80,7 +90,7 @@ describe "when a class extends CascadingClasses" do
|
|
80
90
|
Parent.cascade :has_house
|
81
91
|
end
|
82
92
|
|
83
|
-
all "descendents should reflect
|
93
|
+
all "descendents should reflect nil" do
|
84
94
|
Parent.has_house.must_equal nil
|
85
95
|
Child.has_house.must_equal nil
|
86
96
|
GrandChild.has_house.must_equal nil
|
@@ -102,13 +112,12 @@ describe "when a class extends CascadingClasses" do
|
|
102
112
|
end
|
103
113
|
end
|
104
114
|
|
105
|
-
describe "when a parent has a property with a default
|
115
|
+
describe "when a parent has a property with a default" do
|
106
116
|
before do
|
107
|
-
## Parent.cascade{ :time, :default => 32}
|
108
117
|
Parent.cascade [:time, 32]
|
109
118
|
end
|
110
119
|
|
111
|
-
it "won't matter
|
120
|
+
it "won't matter whether the property is first accessed by the child" do
|
112
121
|
Child.time
|
113
122
|
|
114
123
|
Child.time.must_equal 32
|
@@ -116,7 +125,7 @@ describe "when a class extends CascadingClasses" do
|
|
116
125
|
end
|
117
126
|
end
|
118
127
|
|
119
|
-
describe "when a parent has a property with a default
|
128
|
+
describe "when a parent has a property with a default" do
|
120
129
|
before do
|
121
130
|
Parent.cascade [:time, 32]
|
122
131
|
end
|
@@ -129,5 +138,30 @@ describe "when a class extends CascadingClasses" do
|
|
129
138
|
end
|
130
139
|
end
|
131
140
|
|
132
|
-
|
141
|
+
describe "when a property is set to false" do
|
142
|
+
before do
|
143
|
+
Parent.cascade [:has_time, false]
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should return false, not nil" do
|
147
|
+
Parent.has_time.must_equal false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "when a property name is not allowed" do
|
152
|
+
before do
|
153
|
+
property = CascadingClasses.illegal_names.sample
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should raise a NameError" do
|
157
|
+
res = begin
|
158
|
+
Parent.cascade property
|
159
|
+
rescue NameError
|
160
|
+
true
|
161
|
+
else
|
162
|
+
false
|
163
|
+
end
|
164
|
+
res.must_equal true
|
165
|
+
end
|
166
|
+
end
|
133
167
|
end
|
data/spec/helper_spec.rb
ADDED
data/spec/included_spec.rb
CHANGED
@@ -82,4 +82,16 @@ describe "when CascadingClasses is included by a class" do
|
|
82
82
|
@c.table.must_equal nil
|
83
83
|
end
|
84
84
|
end
|
85
|
+
|
86
|
+
describe "when a property is set to false" do
|
87
|
+
before do
|
88
|
+
A.cascade [:has_time, false]
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should return false, not nil" do
|
92
|
+
A.new.has_time.must_equal false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
|
85
97
|
end
|
data/spec/note.txt
ADDED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cascading_classes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,9 +9,10 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-08-
|
12
|
+
date: 2011-08-08 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
14
|
+
description: Similar to active_support/core_ext/class/attribute.rb but better. Also,
|
15
|
+
doesn't monkey-patch Class
|
15
16
|
email: jeremy.gables@gmail.com
|
16
17
|
executables: []
|
17
18
|
extensions: []
|
@@ -21,9 +22,12 @@ files:
|
|
21
22
|
- Rakefile
|
22
23
|
- lib/cascading_classes.rb
|
23
24
|
- lib/cascading_classes/cascading_classes.rb
|
25
|
+
- lib/cascading_classes/dsl.rb
|
26
|
+
- spec/helper_spec.rb
|
24
27
|
- spec/extended_spec.rb
|
25
28
|
- spec/included_spec.rb
|
26
29
|
- spec/alternative_syntax_spec.rb
|
30
|
+
- spec/note.txt
|
27
31
|
homepage: http://github.com/gables/cascading_classes
|
28
32
|
licenses: []
|
29
33
|
post_install_message:
|
@@ -49,6 +53,8 @@ signing_key:
|
|
49
53
|
specification_version: 3
|
50
54
|
summary: Easily create properties whose values cascade down class trees
|
51
55
|
test_files:
|
56
|
+
- spec/helper_spec.rb
|
52
57
|
- spec/extended_spec.rb
|
53
58
|
- spec/included_spec.rb
|
54
59
|
- spec/alternative_syntax_spec.rb
|
60
|
+
- spec/note.txt
|