bricks 0.4.1 → 0.5.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/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"