once-ler 0.0.10 → 0.0.11
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 +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
|