cascading_classes 0.1.0 → 0.2.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/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
|