once-ler 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +5 -34
- data/lib/onceler/recordable.rb +31 -4
- data/lib/onceler/recorder.rb +1 -19
- metadata +2 -2
data/README.md
CHANGED
@@ -52,14 +52,6 @@ describe "something" do
|
|
52
52
|
end
|
53
53
|
```
|
54
54
|
|
55
|
-
Or even more ambitiously, apply it to all your specs:
|
56
|
-
|
57
|
-
```ruby
|
58
|
-
RSpec.configure do |c|
|
59
|
-
c.onceler!
|
60
|
-
end
|
61
|
-
```
|
62
|
-
|
63
55
|
## How much of a speedup will I get?
|
64
56
|
|
65
57
|
YMMV, it depends on how bad your `let`s/`before`s are. For example,
|
@@ -85,8 +77,11 @@ of activerecord callbacks/inserts/updates.
|
|
85
77
|
[database_cleaner](https://github.com/DatabaseCleaner/database_cleaner))
|
86
78
|
* Your once'd blocks should have no side effects other than database
|
87
79
|
statements, return values, and instance variables.
|
88
|
-
* Your return values and instance variables
|
89
|
-
Marshal.dump
|
80
|
+
* Your return values and instance variables:
|
81
|
+
1. need to be able to handle a `Marshal.dump`/`load` round trip.
|
82
|
+
1. should implement `#==` and `#hash`. for built-ins types (e.g. String)
|
83
|
+
or models, this isn't a problem, but if it's a custom class you might
|
84
|
+
need to add them.
|
90
85
|
* Your once'd blocks' behavior should not depend on side effects of other
|
91
86
|
non-once'd blocks. For example:
|
92
87
|
* a `before(:once)` block should not reference instance variables set by a
|
@@ -96,27 +91,3 @@ of activerecord callbacks/inserts/updates.
|
|
96
91
|
in a particular example), you should ensure they don't conflict with
|
97
92
|
each other (e.g. unique constraint violations, or one `let_once`
|
98
93
|
mutating the return value of another).
|
99
|
-
* Some effort is made to preserve object identity, but just for instance
|
100
|
-
variables and return values, e.g.:
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
let_once(:user) { User.new }
|
104
|
-
let_once(:users) { [user] }
|
105
|
-
|
106
|
-
before(:once) do
|
107
|
-
@joe = user
|
108
|
-
@also_joe = @joe
|
109
|
-
@joe_ish = [@joe]
|
110
|
-
end
|
111
|
-
|
112
|
-
# within an example:
|
113
|
-
# user == @joe => true
|
114
|
-
# user.equal? @joe => true # yay
|
115
|
-
# user == @also_joe => true
|
116
|
-
# user.equal? @also_joe => true # yay
|
117
|
-
# user == users[0] => true
|
118
|
-
# user.equal? users[0] => false # d'oh
|
119
|
-
# user == @joe_ish[0] => true
|
120
|
-
# user.equal? @joe_ish[0] => false # d'oh
|
121
|
-
```
|
122
|
-
|
data/lib/onceler/recordable.rb
CHANGED
@@ -45,17 +45,44 @@ module Onceler
|
|
45
45
|
# we don't include inherited stuff in __data, because we might need to
|
46
46
|
# interleave things from an intermediate before(:each) at run time
|
47
47
|
def __mutated?(key, val)
|
48
|
+
# top-level recorders don't inherit anything, so we always want to return true
|
48
49
|
return true unless @__inherited_cache
|
49
50
|
# need to do both types of comparison, i.e. it's the same object in
|
50
51
|
# memory (not reassigned), and nothing about it has been changed
|
51
|
-
return
|
52
|
-
return
|
53
|
-
|
52
|
+
return true unless @__inherited_values[key].equal?(val)
|
53
|
+
return true unless __values_equal?(@__inherited_cache[key], val)
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
def __values_equal?(obj1, obj2)
|
58
|
+
if ActiveRecord::Base === obj1 && ActiveRecord::Base === obj2
|
59
|
+
cache_key = [obj1, obj2]
|
60
|
+
return @__comparison_cache[cache_key] if @__comparison_cache.key?(cache_key)
|
61
|
+
# so as to avoid cycles while traversing AR associations
|
62
|
+
@__comparison_cache[cache_key] = true
|
63
|
+
@__comparison_cache[cache_key] = obj1.attributes == obj2.attributes &&
|
64
|
+
__associations_equal?(obj1, obj2)
|
65
|
+
else
|
66
|
+
obj1 == obj2
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# if a nested once block updates an inherited object's associations,
|
71
|
+
# we want to know about it
|
72
|
+
def __associations_equal?(obj1, obj2)
|
73
|
+
cache1 = obj1.instance_variable_get(:@association_cache)
|
74
|
+
cache2 = obj2.instance_variable_get(:@association_cache)
|
75
|
+
cache1.all? { |k, v| __values_equal?(v.target, cache2[k].target) }
|
54
76
|
end
|
55
77
|
|
56
78
|
def __data(inherit = false)
|
57
79
|
@__data ||= {}
|
58
|
-
@__data[inherit] ||=
|
80
|
+
@__data[inherit] ||= begin
|
81
|
+
@__comparison_cache = {}
|
82
|
+
data = Marshal.dump([__ivars(inherit), __retvals(inherit)])
|
83
|
+
@__comparison_cache = nil
|
84
|
+
data
|
85
|
+
end
|
59
86
|
end
|
60
87
|
|
61
88
|
def copy_from(other)
|
data/lib/onceler/recorder.rb
CHANGED
@@ -72,33 +72,15 @@ module Onceler
|
|
72
72
|
rollback_transactions!
|
73
73
|
end
|
74
74
|
|
75
|
-
def reconsitute_data!
|
76
|
-
@ivars, @retvals = Marshal.load(@data)
|
77
|
-
identity_map = {}
|
78
|
-
reidentify!(@ivars, identity_map)
|
79
|
-
reidentify!(@retvals, identity_map)
|
80
|
-
end
|
81
|
-
|
82
|
-
def reidentify!(hash, identity_map)
|
83
|
-
hash.each do |key, value|
|
84
|
-
if identity_map.key?(value)
|
85
|
-
hash[key] = identity_map[value]
|
86
|
-
else
|
87
|
-
identity_map[value] = value
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
75
|
def parent
|
93
76
|
@group_class.parent_onceler
|
94
77
|
end
|
95
78
|
|
96
79
|
def replay_into!(instance)
|
97
|
-
|
80
|
+
@ivars, @retvals = Marshal.load(@data)
|
98
81
|
@ivars.each do |key, value|
|
99
82
|
instance.instance_variable_set(key, value)
|
100
83
|
end
|
101
|
-
@retvals
|
102
84
|
end
|
103
85
|
|
104
86
|
# TODO: configurable transaction fu (say, if you have multiple
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: once-ler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
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: 2014-07-
|
12
|
+
date: 2014-07-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|