hairtrigger 0.1.11 → 0.1.12
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.rdoc +28 -2
- data/VERSION +1 -1
- data/lib/hair_trigger/adapter.rb +2 -2
- data/lib/hair_trigger/builder.rb +20 -10
- data/spec/builder_spec.rb +35 -6
- data/spec/schema_dumper_spec.rb +1 -1
- metadata +60 -60
data/README.rdoc
CHANGED
@@ -152,6 +152,29 @@ For MySQL, this will just create a single trigger with conditional logic
|
|
152
152
|
distinct triggers. This same notation is also used within trigger migrations.
|
153
153
|
MySQL does not currently support nested trigger groups.
|
154
154
|
|
155
|
+
=== Database-specific trigger bodies
|
156
|
+
|
157
|
+
Although HairTrigger aims to be totally db-agnostic, at times you do need a
|
158
|
+
little more control over the body of the trigger. You can tailor it for
|
159
|
+
specific databases by returning a hash rather than a string. Make sure to set
|
160
|
+
a :default value if you aren't explicitly specifying all of them.
|
161
|
+
|
162
|
+
For example, MySQL generally performs poorly with subselects in UPDATE
|
163
|
+
statements, and it has its own proprietary syntax for multi-table UPDATEs. So
|
164
|
+
you might do something like the following:
|
165
|
+
|
166
|
+
trigger.after(:insert) do
|
167
|
+
{:default => <<-DEFAULT_SQL, :mysql => <<-MYSQL}
|
168
|
+
|
169
|
+
UPDATE users SET item_count = item_count + 1
|
170
|
+
WHERE id IN (SELECT user_id FROM buckets WHERE id = NEW.bucket_id)
|
171
|
+
DEFAULT_SQL
|
172
|
+
|
173
|
+
UPDATE users, buckets SET item_count = item_count + 1
|
174
|
+
WHERE users.id = user_id AND buckets.id = NEW.bucket_id
|
175
|
+
MYSQL
|
176
|
+
end
|
177
|
+
|
155
178
|
== rake db:schema:dump
|
156
179
|
|
157
180
|
HairTrigger hooks into rake db:schema:dump (and rake tasks that call it) to
|
@@ -228,14 +251,17 @@ you want to support.
|
|
228
251
|
|
229
252
|
== Compatibility
|
230
253
|
|
231
|
-
* Rails 2.3
|
254
|
+
* Rails 2.3 - Rails 3.0.x
|
232
255
|
* Postgres 8.0+
|
233
256
|
* MySQL 5.0.10+
|
234
257
|
* SQLite 3.3.8+
|
235
258
|
|
236
259
|
== Version History
|
237
260
|
|
238
|
-
* 0.1.
|
261
|
+
* 0.1.12 DB-specific trigger body support, bugfixes
|
262
|
+
* 0.1.11 Safer migration loading, some speedups
|
263
|
+
* 0.1.10 Sped up migration evaluation
|
264
|
+
* 0.1.9 MySQL fixes for inferred root@localhost
|
239
265
|
* 0.1.7 Rails 3 support, fixed a couple manual create_trigger bugs
|
240
266
|
* 0.1.6 rake db:schema:dump support, respect non-timestamped migrations
|
241
267
|
* 0.1.4 Compatibility tracking, fixed Postgres return bug, ensure last action
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.12
|
data/lib/hair_trigger/adapter.rb
CHANGED
@@ -5,11 +5,11 @@ module HairTrigger
|
|
5
5
|
options = name
|
6
6
|
name = nil
|
7
7
|
end
|
8
|
-
::HairTrigger::Builder.new(name, options.merge(:execute => true))
|
8
|
+
::HairTrigger::Builder.new(name, options.merge(:execute => true, :adapter => self))
|
9
9
|
end
|
10
10
|
|
11
11
|
def drop_trigger(name, table, options = {})
|
12
|
-
::HairTrigger::Builder.new(name, options.merge(:execute => true, :drop => true, :table => table)){}
|
12
|
+
::HairTrigger::Builder.new(name, options.merge(:execute => true, :drop => true, :table => table, :adapter => self)).all{}
|
13
13
|
end
|
14
14
|
|
15
15
|
def triggers(options = {})
|
data/lib/hair_trigger/builder.rb
CHANGED
@@ -98,6 +98,10 @@ module HairTrigger
|
|
98
98
|
options[:events] = events.map{ |e| e.to_s.upcase }
|
99
99
|
end
|
100
100
|
|
101
|
+
def raw_actions
|
102
|
+
@raw_actions ||= prepared_actions.is_a?(Hash) ? prepared_actions[adapter_name] || prepared_actions[:default] : prepared_actions
|
103
|
+
end
|
104
|
+
|
101
105
|
def prepared_name
|
102
106
|
@prepared_name ||= options[:name] ||= infer_name
|
103
107
|
end
|
@@ -141,7 +145,11 @@ module HairTrigger
|
|
141
145
|
def prepare!
|
142
146
|
@triggers.each(&:prepare!) if @triggers
|
143
147
|
@prepared_where = options[:where] = interpolate(options[:where]) if options[:where]
|
144
|
-
|
148
|
+
if @actions
|
149
|
+
@prepared_actions = @actions.is_a?(Hash) ?
|
150
|
+
@actions.inject({}){ |hash, (key, value)| hash[key] = interpolate(value).rstrip; hash } :
|
151
|
+
interpolate(@actions).rstrip
|
152
|
+
end
|
145
153
|
end
|
146
154
|
|
147
155
|
def validate!(direction = :down)
|
@@ -166,7 +174,7 @@ module HairTrigger
|
|
166
174
|
if options[:drop]
|
167
175
|
generate_drop_trigger
|
168
176
|
else
|
169
|
-
raise GenerationError, "no actions specified" if @triggers && create_grouped_trigger? ? @triggers.any?{ |t| t.
|
177
|
+
raise GenerationError, "no actions specified" if @triggers && create_grouped_trigger? ? @triggers.any?{ |t| t.raw_actions.nil? } : raw_actions.nil?
|
170
178
|
raise GenerationError, "need to specify the event(s) (:insert, :update, :delete)" if !options[:events] || options[:events].empty?
|
171
179
|
raise GenerationError, "need to specify the timing (:before/:after)" unless options[:timing]
|
172
180
|
|
@@ -255,7 +263,7 @@ module HairTrigger
|
|
255
263
|
end
|
256
264
|
|
257
265
|
def actions_to_ruby(indent = '')
|
258
|
-
if prepared_actions =~ /\n/
|
266
|
+
if prepared_actions.is_a?(String) && prepared_actions =~ /\n/
|
259
267
|
"#{indent}<<-SQL_ACTIONS\n#{prepared_actions}\n#{indent}SQL_ACTIONS"
|
260
268
|
else
|
261
269
|
indent + prepared_actions.inspect
|
@@ -271,7 +279,9 @@ module HairTrigger
|
|
271
279
|
raise DeclarationError, "trigger group did not define any triggers" if @triggers.empty?
|
272
280
|
else
|
273
281
|
@actions = block.call
|
274
|
-
@actions.
|
282
|
+
(@actions.is_a?(Hash) ? @actions.values : [@actions]).each do |actions|
|
283
|
+
actions.sub!(/(\s*)\z/, ';\1') if actions && actions !~ /;\s*\z/
|
284
|
+
end
|
275
285
|
end
|
276
286
|
# only the top-most block actually executes
|
277
287
|
Array(generate).each{ |action| adapter.execute(action)} if options[:execute] && !@trigger_group
|
@@ -312,7 +322,7 @@ module HairTrigger
|
|
312
322
|
CREATE TRIGGER #{prepared_name} #{options[:timing]} #{options[:events]} ON #{options[:table]}
|
313
323
|
FOR EACH #{options[:for_each]}#{prepared_where ? " WHEN " + prepared_where : ''}
|
314
324
|
BEGIN
|
315
|
-
#{normalize(
|
325
|
+
#{normalize(raw_actions, 1).rstrip}
|
316
326
|
END;
|
317
327
|
SQL
|
318
328
|
end
|
@@ -328,13 +338,13 @@ BEGIN
|
|
328
338
|
SQL
|
329
339
|
if prepared_where && db_version < 90000
|
330
340
|
sql << normalize("IF #{prepared_where} THEN", 1)
|
331
|
-
sql << normalize(
|
341
|
+
sql << normalize(raw_actions, 2)
|
332
342
|
sql << normalize("END IF;", 1)
|
333
343
|
else
|
334
|
-
sql << normalize(
|
344
|
+
sql << normalize(raw_actions, 1)
|
335
345
|
end
|
336
346
|
# if no return is specified at the end, be sure we set a sane one
|
337
|
-
unless
|
347
|
+
unless raw_actions =~ /return [^;]+;\s*\z/i
|
338
348
|
if options[:timing] == "AFTER" || options[:for_each] == 'STATEMENT'
|
339
349
|
sql << normalize("RETURN NULL;", 1)
|
340
350
|
elsif options[:events].include?('DELETE')
|
@@ -363,10 +373,10 @@ BEGIN
|
|
363
373
|
(@triggers ? @triggers : [self]).each do |trigger|
|
364
374
|
if trigger.prepared_where
|
365
375
|
sql << normalize("IF #{trigger.prepared_where} THEN", 1)
|
366
|
-
sql << normalize(trigger.
|
376
|
+
sql << normalize(trigger.raw_actions, 2)
|
367
377
|
sql << normalize("END IF;", 1)
|
368
378
|
else
|
369
|
-
sql << normalize(trigger.
|
379
|
+
sql << normalize(trigger.raw_actions, 1)
|
370
380
|
end
|
371
381
|
end
|
372
382
|
sql << "END\n";
|
data/spec/builder_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rspec'
|
2
|
-
require '
|
2
|
+
require 'active_record'
|
3
|
+
require 'hair_trigger'
|
3
4
|
|
4
5
|
HairTrigger::Builder.show_warnings = false
|
5
6
|
|
@@ -29,7 +30,7 @@ describe "builder" do
|
|
29
30
|
it "should tack on a semicolon if none is provided" do
|
30
31
|
@adapter = MockAdapter.new("mysql")
|
31
32
|
builder.on(:foos).after(:update){ "FOO " }.generate.
|
32
|
-
|
33
|
+
grep(/FOO;/).size.should eql(1)
|
33
34
|
end
|
34
35
|
end
|
35
36
|
|
@@ -37,16 +38,44 @@ describe "builder" do
|
|
37
38
|
it "should view identical triggers as identical" do
|
38
39
|
@adapter = MockAdapter.new("mysql")
|
39
40
|
builder.on(:foos).after(:update){ "FOO" }.
|
40
|
-
|
41
|
+
should eql(builder.on(:foos).after(:update){ "FOO" })
|
41
42
|
end
|
42
43
|
|
43
44
|
it "should view incompatible triggers as different" do
|
44
45
|
@adapter = MockAdapter.new("mysql")
|
45
46
|
HairTrigger::Builder.new(nil, :adapter => @adapter, :compatibility => 0).on(:foos).after(:update){ "FOO" }.
|
46
|
-
|
47
|
+
should_not eql(builder.on(:foos).after(:update){ "FOO" })
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
51
|
+
context "adapter-specific actions" do
|
52
|
+
before(:each) do
|
53
|
+
@adapter = MockAdapter.new("mysql")
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should generate the appropriate trigger for the adapter" do
|
57
|
+
sql = builder.on(:foos).after(:update).where('BAR'){
|
58
|
+
{:default => "DEFAULT", :mysql => "MYSQL"}
|
59
|
+
}.generate
|
60
|
+
|
61
|
+
sql.grep(/DEFAULT/).size.should eql(0)
|
62
|
+
sql.grep(/MYSQL/).size.should eql(1)
|
63
|
+
|
64
|
+
sql = builder.on(:foos).after(:update).where('BAR'){
|
65
|
+
{:default => "DEFAULT", :postgres => "POSTGRES"}
|
66
|
+
}.generate
|
67
|
+
|
68
|
+
sql.grep(/POSTGRES/).size.should eql(0)
|
69
|
+
sql.grep(/DEFAULT/).size.should eql(1)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should complain if no actions are provided for this adapter" do
|
73
|
+
lambda {
|
74
|
+
builder.on(:foos).after(:update).where('BAR'){ {:postgres => "POSTGRES"} }.generate
|
75
|
+
}.should raise_error
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
50
79
|
context "mysql" do
|
51
80
|
before(:each) do
|
52
81
|
@adapter = MockAdapter.new("mysql")
|
@@ -156,7 +185,7 @@ describe "builder" do
|
|
156
185
|
|
157
186
|
it "should allow truncate with for_each statement" do
|
158
187
|
builder.on(:foos).after(:truncate).for_each(:statement){ "FOO" }.generate.
|
159
|
-
|
188
|
+
grep(/TRUNCATE.*FOR EACH STATEMENT/m).size.should eql(1)
|
160
189
|
end
|
161
190
|
|
162
191
|
it "should reject truncate with for_each row" do
|
@@ -167,7 +196,7 @@ describe "builder" do
|
|
167
196
|
|
168
197
|
it "should add a return statement if none is provided" do
|
169
198
|
builder.on(:foos).after(:update){ "FOO" }.generate.
|
170
|
-
|
199
|
+
grep(/RETURN NULL;/).size.should eql(1)
|
171
200
|
end
|
172
201
|
|
173
202
|
context "legacy" do
|
data/spec/schema_dumper_spec.rb
CHANGED
@@ -73,7 +73,7 @@ describe "schema" do
|
|
73
73
|
# edit our model trigger, generate and apply a new migration
|
74
74
|
user_model = File.read(HairTrigger.model_path + '/user.rb')
|
75
75
|
File.open(HairTrigger.model_path + '/user.rb', 'w') { |f|
|
76
|
-
f.write user_model.sub('UPDATE groups SET bob_count = bob_count + 1', 'UPDATE groups SET bob_count = bob_count + 2')
|
76
|
+
f.write user_model.sub('"UPDATE groups SET bob_count = bob_count + 1"', '{:default => "UPDATE groups SET bob_count = bob_count + 2"}')
|
77
77
|
}
|
78
78
|
migration = HairTrigger.generate_migration
|
79
79
|
ActiveRecord::Migrator.migrate(HairTrigger.migration_path)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hairtrigger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
9
|
+
- 12
|
10
|
+
version: 0.1.12
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Jon Jensen
|
@@ -15,13 +15,11 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-11-08 00:00:00 -07:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
|
23
|
-
type: :runtime
|
24
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
25
23
|
none: false
|
26
24
|
requirements:
|
27
25
|
- - ">="
|
@@ -32,12 +30,12 @@ dependencies:
|
|
32
30
|
- 3
|
33
31
|
- 0
|
34
32
|
version: 2.3.0
|
35
|
-
name: activerecord
|
36
|
-
version_requirements: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
33
|
prerelease: false
|
39
34
|
type: :runtime
|
40
|
-
requirement:
|
35
|
+
requirement: *id001
|
36
|
+
name: activerecord
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
41
39
|
none: false
|
42
40
|
requirements:
|
43
41
|
- - "="
|
@@ -48,12 +46,12 @@ dependencies:
|
|
48
46
|
- 0
|
49
47
|
- 6
|
50
48
|
version: 2.0.6
|
51
|
-
name: ruby_parser
|
52
|
-
version_requirements: *id002
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
49
|
prerelease: false
|
55
50
|
type: :runtime
|
56
|
-
requirement:
|
51
|
+
requirement: *id002
|
52
|
+
name: ruby_parser
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
57
55
|
none: false
|
58
56
|
requirements:
|
59
57
|
- - "="
|
@@ -64,12 +62,12 @@ dependencies:
|
|
64
62
|
- 2
|
65
63
|
- 5
|
66
64
|
version: 1.2.5
|
65
|
+
prerelease: false
|
66
|
+
type: :runtime
|
67
|
+
requirement: *id003
|
67
68
|
name: ruby2ruby
|
68
|
-
version_requirements: *id003
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
|
71
|
-
type: :development
|
72
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
70
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
73
71
|
none: false
|
74
72
|
requirements:
|
75
73
|
- - ~>
|
@@ -80,12 +78,12 @@ dependencies:
|
|
80
78
|
- 3
|
81
79
|
- 0
|
82
80
|
version: 2.3.0
|
83
|
-
name: rspec
|
84
|
-
version_requirements: *id004
|
85
|
-
- !ruby/object:Gem::Dependency
|
86
81
|
prerelease: false
|
87
82
|
type: :development
|
88
|
-
requirement:
|
83
|
+
requirement: *id004
|
84
|
+
name: rspec
|
85
|
+
- !ruby/object:Gem::Dependency
|
86
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
89
87
|
none: false
|
90
88
|
requirements:
|
91
89
|
- - ~>
|
@@ -96,12 +94,12 @@ dependencies:
|
|
96
94
|
- 0
|
97
95
|
- 0
|
98
96
|
version: 1.0.0
|
99
|
-
name: bundler
|
100
|
-
version_requirements: *id005
|
101
|
-
- !ruby/object:Gem::Dependency
|
102
97
|
prerelease: false
|
103
98
|
type: :development
|
104
|
-
requirement:
|
99
|
+
requirement: *id005
|
100
|
+
name: bundler
|
101
|
+
- !ruby/object:Gem::Dependency
|
102
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
105
103
|
none: false
|
106
104
|
requirements:
|
107
105
|
- - ~>
|
@@ -112,12 +110,12 @@ dependencies:
|
|
112
110
|
- 6
|
113
111
|
- 1
|
114
112
|
version: 1.6.1
|
115
|
-
name: jeweler
|
116
|
-
version_requirements: *id006
|
117
|
-
- !ruby/object:Gem::Dependency
|
118
113
|
prerelease: false
|
119
114
|
type: :development
|
120
|
-
requirement:
|
115
|
+
requirement: *id006
|
116
|
+
name: jeweler
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
121
119
|
none: false
|
122
120
|
requirements:
|
123
121
|
- - ">="
|
@@ -126,12 +124,12 @@ dependencies:
|
|
126
124
|
segments:
|
127
125
|
- 0
|
128
126
|
version: "0"
|
129
|
-
name: rcov
|
130
|
-
version_requirements: *id007
|
131
|
-
- !ruby/object:Gem::Dependency
|
132
127
|
prerelease: false
|
133
128
|
type: :development
|
134
|
-
requirement:
|
129
|
+
requirement: *id007
|
130
|
+
name: rcov
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
135
133
|
none: false
|
136
134
|
requirements:
|
137
135
|
- - ">="
|
@@ -142,12 +140,12 @@ dependencies:
|
|
142
140
|
- 8
|
143
141
|
- 1
|
144
142
|
version: 2.8.1
|
145
|
-
name: mysql
|
146
|
-
version_requirements: *id008
|
147
|
-
- !ruby/object:Gem::Dependency
|
148
143
|
prerelease: false
|
149
144
|
type: :development
|
150
|
-
requirement:
|
145
|
+
requirement: *id008
|
146
|
+
name: mysql
|
147
|
+
- !ruby/object:Gem::Dependency
|
148
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
151
149
|
none: false
|
152
150
|
requirements:
|
153
151
|
- - <
|
@@ -165,12 +163,12 @@ dependencies:
|
|
165
163
|
- 2
|
166
164
|
- 7
|
167
165
|
version: 0.2.7
|
168
|
-
name: mysql2
|
169
|
-
version_requirements: *id009
|
170
|
-
- !ruby/object:Gem::Dependency
|
171
166
|
prerelease: false
|
172
167
|
type: :development
|
173
|
-
requirement:
|
168
|
+
requirement: *id009
|
169
|
+
name: mysql2
|
170
|
+
- !ruby/object:Gem::Dependency
|
171
|
+
version_requirements: &id010 !ruby/object:Gem::Requirement
|
174
172
|
none: false
|
175
173
|
requirements:
|
176
174
|
- - ">="
|
@@ -181,12 +179,12 @@ dependencies:
|
|
181
179
|
- 10
|
182
180
|
- 1
|
183
181
|
version: 0.10.1
|
184
|
-
name: pg
|
185
|
-
version_requirements: *id010
|
186
|
-
- !ruby/object:Gem::Dependency
|
187
182
|
prerelease: false
|
188
183
|
type: :development
|
189
|
-
requirement:
|
184
|
+
requirement: *id010
|
185
|
+
name: pg
|
186
|
+
- !ruby/object:Gem::Dependency
|
187
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
190
188
|
none: false
|
191
189
|
requirements:
|
192
190
|
- - ">="
|
@@ -197,12 +195,12 @@ dependencies:
|
|
197
195
|
- 3
|
198
196
|
- 2
|
199
197
|
version: 1.3.2
|
200
|
-
name: sqlite3-ruby
|
201
|
-
version_requirements: *id011
|
202
|
-
- !ruby/object:Gem::Dependency
|
203
198
|
prerelease: false
|
204
199
|
type: :development
|
205
|
-
requirement:
|
200
|
+
requirement: *id011
|
201
|
+
name: sqlite3-ruby
|
202
|
+
- !ruby/object:Gem::Dependency
|
203
|
+
version_requirements: &id012 !ruby/object:Gem::Requirement
|
206
204
|
none: false
|
207
205
|
requirements:
|
208
206
|
- - "="
|
@@ -213,12 +211,12 @@ dependencies:
|
|
213
211
|
- 10
|
214
212
|
- 4
|
215
213
|
version: 0.10.4
|
214
|
+
prerelease: false
|
215
|
+
type: :development
|
216
|
+
requirement: *id012
|
216
217
|
name: ruby-debug
|
217
|
-
version_requirements: *id012
|
218
218
|
- !ruby/object:Gem::Dependency
|
219
|
-
|
220
|
-
type: :runtime
|
221
|
-
requirement: &id013 !ruby/object:Gem::Requirement
|
219
|
+
version_requirements: &id013 !ruby/object:Gem::Requirement
|
222
220
|
none: false
|
223
221
|
requirements:
|
224
222
|
- - ">="
|
@@ -229,12 +227,12 @@ dependencies:
|
|
229
227
|
- 3
|
230
228
|
- 0
|
231
229
|
version: 2.3.0
|
230
|
+
prerelease: false
|
231
|
+
type: :runtime
|
232
|
+
requirement: *id013
|
232
233
|
name: activerecord
|
233
|
-
version_requirements: *id013
|
234
234
|
- !ruby/object:Gem::Dependency
|
235
|
-
|
236
|
-
type: :development
|
237
|
-
requirement: &id014 !ruby/object:Gem::Requirement
|
235
|
+
version_requirements: &id014 !ruby/object:Gem::Requirement
|
238
236
|
none: false
|
239
237
|
requirements:
|
240
238
|
- - ~>
|
@@ -245,8 +243,10 @@ dependencies:
|
|
245
243
|
- 3
|
246
244
|
- 0
|
247
245
|
version: 2.3.0
|
246
|
+
prerelease: false
|
247
|
+
type: :development
|
248
|
+
requirement: *id014
|
248
249
|
name: rspec
|
249
|
-
version_requirements: *id014
|
250
250
|
description: allows you to declare database triggers in ruby in your models, and then generate appropriate migrations as they change
|
251
251
|
email: jenseng@gmail.com
|
252
252
|
executables: []
|