bricks 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.md CHANGED
@@ -1,6 +1,12 @@
1
1
  History
2
2
  =======
3
3
 
4
+ 0.5.0
5
+ -----
6
+
7
+ * Now includes generalized hook framework, but only supports after(:clone) hook.
8
+ * Ask for an attribute that hasn't been initialized yet, and it will be.
9
+
4
10
  0.4.1
5
11
  -----
6
12
 
data/README.md CHANGED
@@ -18,6 +18,7 @@ We'll use the following domain to describe *Brick's* features:
18
18
  # title :string(255)
19
19
  # author :string(255)
20
20
  # formatted_title :string(510)
21
+ # popularity :integer(4)
21
22
  # publication_id :integer(4)
22
23
  #
23
24
  class Article < ActiveRecord::Base
@@ -244,6 +245,30 @@ Note that if you want to override a *-to-many association inside a trait, you ne
244
245
 
245
246
  For an executable version of this documentation, please see spec/bricks_spec.rb.
246
247
 
248
+ ### Hooks
249
+
250
+ *Bricks includes a simple, general hook framework. It allows you to do something like this:
251
+
252
+ builder Article
253
+ # ...
254
+
255
+ trait :on_the_bugle do
256
+ publication.name "The Daily Bugle"
257
+ popularity 75
258
+ end
259
+
260
+ trait :on_the_planet do
261
+ publication.name "The Daily Planet"
262
+ popularity 85
263
+ end
264
+
265
+ after :clone do
266
+ send %w(on_the_bugle on_the_planet)[rand(2)]
267
+ end
268
+ end
269
+
270
+ *Bricks* supports a single hook right now: after(:clone). It will be executed whenever you use any of #build, #build!, #create or #create!, right before you start customizing the resulting builder on your test.
271
+
247
272
  Installation
248
273
  ------------
249
274
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.4.1
1
+ 0.5.0
data/bricks.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bricks}
8
- s.version = "0.4.1"
8
+ s.version = "0.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["David Leal"]
12
- s.date = %q{2011-06-23}
12
+ s.date = %q{2011-06-29}
13
13
  s.email = %q{david@mojotech.com}
14
14
  s.extra_rdoc_files = [
15
15
  "LICENSE.txt",
@@ -23,6 +23,12 @@ module Bricks
23
23
  self
24
24
  end
25
25
 
26
+ def after(hook, &block)
27
+ @traits.class_eval do
28
+ define_method "__after_#{hook}", &block
29
+ end
30
+ end
31
+
26
32
  def derive(args = {})
27
33
  build_attrs
28
34
 
@@ -30,7 +36,9 @@ module Bricks
30
36
  save = args.has_key?(:save) ? args[:save] : @save
31
37
  search = args.has_key?(:search) ? args[:search] : @search
32
38
 
33
- Builder.new(klass, @attrs, @traits, save, search)
39
+ Builder.new(klass, @attrs, @traits, save, search).tap { |b|
40
+ b.run_hook :after, :clone if ! args[:class]
41
+ }
34
42
  end
35
43
 
36
44
  def initialize(
@@ -80,7 +88,8 @@ module Bricks
80
88
  elsif settable?(attr)
81
89
  set attr, *args, &block
82
90
  else
83
- raise Bricks::NoAttributeOrTrait, "Can't find `#{name}'."
91
+ raise Bricks::NoAttributeOrTrait,
92
+ "Can't find `#{name}' on builder for #{@class}."
84
93
  end
85
94
 
86
95
  if return_object
@@ -93,6 +102,14 @@ module Bricks
93
102
  end
94
103
  end
95
104
 
105
+ protected
106
+
107
+ def run_hook(position, name)
108
+ full_name = "__#{position}_#{name}"
109
+
110
+ send full_name if respond_to?(full_name)
111
+ end
112
+
96
113
  private
97
114
 
98
115
  def subject
@@ -113,23 +130,53 @@ module Bricks
113
130
  obj.save!
114
131
  end
115
132
 
116
- def initialize_object(parent)
117
- obj = @class.new
133
+ class Proxy
134
+ attr_reader :obj
135
+
136
+ def initialize(obj, attrs, parent)
137
+ @obj = obj
138
+ @attrs_in = attrs.dup
139
+ @attrs_out = {}
140
+ @parent = parent
141
+ end
118
142
 
119
- @attrs.each { |(k, v)|
120
- val = case v
143
+ def method_missing(name, *args)
144
+ name_y = name.to_sym
145
+
146
+ if @attrs_in.assoc(name_y) && ! @attrs_out.has_key?(name_y)
147
+ fix_attr name
148
+ else
149
+ @obj.send name, *args
150
+ end
151
+ end
152
+
153
+ def build
154
+ @attrs_in.each { |(k, _)| send k }
155
+
156
+ @obj
157
+ end
158
+
159
+ def fix_attr(name)
160
+ val = case v = @attrs_in.assoc(name).last
121
161
  when Proc
122
- v.call *[obj, parent].take([v.arity, 0].max)
162
+ case r = v.call(*[self, @parent].take([v.arity, 0].max))
163
+ when Proxy
164
+ r.obj
165
+ else
166
+ r
167
+ end
123
168
  when Builder, BuilderSet
124
- v.generate(:parent => obj)
169
+ v.generate(:parent => self)
125
170
  else
126
171
  v
127
172
  end
128
173
 
129
- obj.send "#{k}=", val
130
- }
174
+ @attrs_out[name] = @obj.send("#{name}=", val)
175
+ end
176
+ end
131
177
 
132
- obj
178
+ def initialize_object(parent)
179
+ Proxy.new(@class.new, @attrs, parent).build
133
180
  end
134
181
 
135
182
  def settable?(name)
@@ -11,7 +11,7 @@ describe Bricks::Builder do
11
11
  }.new
12
12
 
13
13
  class Person
14
- attr_accessor :name
14
+ attr_accessor :name, :first_name, :last_name
15
15
  end
16
16
  end
17
17
 
@@ -38,4 +38,19 @@ describe Bricks::Builder do
38
38
 
39
39
  b.generate.object_id.should_not == b.generate.object_id
40
40
  end
41
+
42
+ describe "attribute evaluation ordering" do
43
+ before :all do
44
+ end
45
+
46
+ it "doesn't care which order the attributes are declared" do
47
+ b = Bricks::Builder.new Person do
48
+ name { |obj| obj.first_name + " " + obj.last_name }
49
+ first_name { "Jack" }
50
+ last_name { "Black" }
51
+ end
52
+
53
+ b.derive.generate.name.should == "Jack Black"
54
+ end
55
+ end
41
56
  end
data/spec/bricks_spec.rb CHANGED
@@ -44,6 +44,10 @@ describe Bricks do
44
44
 
45
45
  %w(Tom Dick Harry).each { |n| readers.name(n) }
46
46
  end
47
+
48
+ after :clone do
49
+ popularity (1..100).to_a[rand(100)]
50
+ end
47
51
  end
48
52
 
49
53
  builder Newspaper do
@@ -217,5 +221,15 @@ describe Bricks do
217
221
  build!(Reader).should be_a(Reader)
218
222
  end
219
223
  end
224
+
225
+ describe "hooks" do
226
+ it "executes the `generate' hook after a builder is cloned" do
227
+ build!(Article).popularity.should_not == build!(Article).popularity
228
+ end
229
+
230
+ it "it does not override values set after the builder is cloned" do
231
+ build(Article).popularity!(50).popularity.should == 50
232
+ end
233
+ end
220
234
  end
221
235
 
@@ -17,6 +17,7 @@ ActiveRecord::Schema.define(:version => 20110608204150) do
17
17
  t.string "language"
18
18
  t.integer "newspaper_id"
19
19
  t.string "title"
20
+ t.integer "popularity"
20
21
  end
21
22
 
22
23
  create_table "newspapers", :force => true do |t|
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: bricks
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.4.1
5
+ version: 0.5.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - David Leal
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-23 00:00:00 +01:00
13
+ date: 2011-06-29 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -101,7 +101,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
- hash: -949772447
104
+ hash: -614702947
105
105
  segments:
106
106
  - 0
107
107
  version: "0"