hairtrigger 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,31 +7,8 @@ and a simple rake task does all the dirty work for you.
7
7
 
8
8
  ## Installation
9
9
 
10
- ### Rails 3 or 4
11
-
12
- If you are using Rails 3 or 4, just `gem 'hairtrigger'`
13
-
14
- ### Rails 2
15
-
16
- #### Step 1.
17
-
18
- Put hairtrigger in your Gemfile, or if you're not using bundler, you can
19
- `gem install hairtrigger` and then put hairtrigger in environment.rb
20
-
21
- #### Step 2.
22
-
23
- Create lib/tasks/hair_trigger.rake with the following:
24
-
25
- ```ruby
26
- $VERBOSE = nil
27
- Dir["#{Gem::Specification.find_by_name('hairtrigger').full_gem_path}/lib/tasks/*.rake"].each { |ext| load ext }
28
- ```
29
-
30
- This will give you the `db:generate_trigger_migration` task, and will ensure
31
- that hairtrigger hooks into `db:schema:dump`.
32
-
33
- If you are unpacking the gem in vendor/plugins, this step is not needed
34
- (though you'll then want to delete its Gemfile to avoid possible conflicts).
10
+ If you are using Rails 3 or beyond, just add `gem 'hairtrigger'` to your
11
+ Gemfile. For Rails 2, it's [slightly more involved](RAILS2.md)
35
12
 
36
13
  ## Usage
37
14
 
@@ -135,6 +112,11 @@ For MySQL, this will just create a single trigger with conditional logic
135
112
  distinct triggers. This same notation is also used within trigger migrations.
136
113
  MySQL does not currently support nested trigger groups.
137
114
 
115
+ Because of these differences in how the triggers are created, take care
116
+ when setting the `name` for triggers or groups. In other words,
117
+ PostgreSQL/SQLite will use the `name`s specified on the individual
118
+ triggers; MySQL will use the `name` specified on the group.
119
+
138
120
  ### Database-specific trigger bodies
139
121
 
140
122
  Although HairTrigger aims to be totally db-agnostic, at times you do need a
@@ -173,6 +155,11 @@ create_trigger(:compatibility => 1).on(:users).after(:insert) do
173
155
  end
174
156
  ```
175
157
 
158
+ Because `create_trigger` may drop an existing trigger of the same name,
159
+ you need to actually implement `up`/`down` methods in your migration
160
+ (rather than `change`) so that it does the right thing when
161
+ rolling back.
162
+
176
163
  #### Manual triggers and :compatibility
177
164
 
178
165
  As bugs are fixed and features are implemented in hairtrigger, it's possible
data/lib/hair_trigger.rb CHANGED
@@ -70,7 +70,7 @@ module HairTrigger
70
70
  if previous_schema = (options.has_key?(:previous_schema) ? options[:previous_schema] : File.exist?(schema_rb_path) && File.read(schema_rb_path))
71
71
  base_triggers = MigrationReader.get_triggers(previous_schema, options)
72
72
  unless base_triggers.empty?
73
- version = (previous_schema =~ /ActiveRecord::Schema\.define\(:version => (\d+)\)/) && $1.to_i
73
+ version = (previous_schema =~ /ActiveRecord::Schema\.define\(.*?(\d+)\)/) && $1.to_i
74
74
  migrations.unshift [OpenStruct.new({:version => version}), base_triggers]
75
75
  end
76
76
  end
@@ -15,6 +15,7 @@ module HairTrigger
15
15
  @options = {}
16
16
  @chained_calls = []
17
17
  @errors = []
18
+ @warnings = []
18
19
  set_name(name) if name
19
20
  {:timing => :after, :for_each => :row}.update(options).each do |key, value|
20
21
  if respond_to?("set_#{key}")
@@ -30,6 +31,7 @@ module HairTrigger
30
31
  @triggers = nil
31
32
  @chained_calls = []
32
33
  @errors = []
34
+ @warnings = []
33
35
  @options = @options.dup
34
36
  @options.delete(:name) # this will be inferred (or set further down the line)
35
37
  @options.each do |key, value|
@@ -112,9 +114,15 @@ module HairTrigger
112
114
  [prepared_name] + (@triggers ? @triggers.map(&:prepared_name) : [])
113
115
  end
114
116
 
117
+ def all_triggers(include_self = true)
118
+ triggers = []
119
+ triggers << self if include_self
120
+ (@triggers || []).map(&:all_triggers).inject(triggers, &:concat)
121
+ end
122
+
115
123
  def self.chainable_methods(*methods)
116
124
  methods.each do |method|
117
- class_eval <<-METHOD
125
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
118
126
  alias #{method}_orig #{method}
119
127
  def #{method}(*args)
120
128
  @chained_calls << :#{method}
@@ -128,7 +136,7 @@ module HairTrigger
128
136
  @chained_calls.pop # the subtrigger will get this, we don't need it
129
137
  @chained_calls = @chained_calls.uniq
130
138
  @triggers << trigger = clone
131
- trigger.#{method}(*args, &Proc.new)
139
+ trigger.#{method}(*args, &(block_given? ? Proc.new : nil))
132
140
  else
133
141
  #{method}_orig(*args)
134
142
  maybe_execute(&Proc.new) if block_given?
@@ -160,6 +168,10 @@ module HairTrigger
160
168
  raise GenerationError, error if adapters.include?(adapter_name)
161
169
  $stderr.puts "WARNING: " + error if self.class.show_warnings
162
170
  end
171
+ @warnings.each do |(error, *adapters)|
172
+ $stderr.puts "WARNING: " + error if adapters.include?(adapter_name) && self.class.show_warnings
173
+ end
174
+
163
175
  if direction != :up
164
176
  @triggers.each{ |t| t.validate!(:down) } if @triggers
165
177
  end
@@ -247,7 +259,11 @@ module HairTrigger
247
259
  end
248
260
 
249
261
  def errors
250
- (@triggers || []).inject(@errors){ |errors, t| errors + t.errors }
262
+ (@triggers || []).map(&:errors).inject(@errors, &:+)
263
+ end
264
+
265
+ def warnings
266
+ (@triggers || []).map(&:warnings).inject(@warnings, &:+)
251
267
  end
252
268
 
253
269
  private
@@ -289,10 +305,25 @@ module HairTrigger
289
305
  end
290
306
  end
291
307
  # only the top-most block actually executes
292
- Array(generate).each{ |action| adapter.execute(action)} if options[:execute] && !@trigger_group
308
+ if !@trigger_group
309
+ validate_names!
310
+ if options[:execute]
311
+ Array(generate).each{ |action| adapter.execute(action)}
312
+ end
313
+ end
293
314
  self
294
315
  end
295
316
 
317
+ def validate_names!
318
+ subtriggers = all_triggers(false)
319
+ named_subtriggers = subtriggers.select{ |t| t.options[:name] }
320
+ if named_subtriggers.present? && !options[:name]
321
+ @warnings << ["nested triggers have explicit names, but trigger group does not. trigger name will be inferred", :mysql]
322
+ elsif subtriggers.present? && !named_subtriggers.present? && options[:name]
323
+ @warnings << ["trigger group has an explicit name, but nested triggers do not. trigger names will be inferred", :postgresql, :sqlite]
324
+ end
325
+ end
326
+
296
327
  def adapter_name
297
328
  @adapter_name ||= HairTrigger.adapter_name_for(adapter)
298
329
  end
@@ -23,6 +23,7 @@ module HairTrigger
23
23
  # find the block of the up method
24
24
  sexps = sexps.last if sexps.last.is_a?(Sexp) && sexps.last[0] == :block
25
25
  sexps = sexps.detect{ |s| s.is_a?(Sexp) && (s[0] == :defs && s[1] && s[1][0] == :self && s[2] == :up || s[0] == :defn && s[1] == :up) }
26
+ return [] unless sexps # no `up` method... unsupported `change` perhaps?
26
27
  sexps.each do |sexp|
27
28
  next unless (method = extract_method_call(sexp)) && [:create_trigger, :drop_trigger].include?(method)
28
29
  trigger = instance_eval("generate_" + generator.process(sexp))
@@ -32,6 +33,7 @@ module HairTrigger
32
33
  triggers
33
34
  rescue
34
35
  $stderr.puts "Error reading triggers in #{source.filename rescue "schema.rb"}: #{$!}"
36
+ []
35
37
  end
36
38
 
37
39
  private
@@ -48,6 +50,7 @@ module HairTrigger
48
50
  def generate_create_trigger(*arguments)
49
51
  arguments.unshift({}) if arguments.empty?
50
52
  arguments.unshift(nil) if arguments.first.is_a?(Hash)
53
+ arguments.push({}) if arguments.size == 1
51
54
  arguments[1][:compatibility] ||= HairTrigger::Builder.base_compatibility
52
55
  ::HairTrigger::Builder.new(*arguments)
53
56
  end
@@ -1,8 +1,12 @@
1
1
  module HairTrigger
2
2
  module SchemaDumper
3
3
  def trailer_with_triggers(stream)
4
+ orig_show_warnings = Builder.show_warnings
5
+ Builder.show_warnings = false # we already show them when running the migration
4
6
  triggers(stream)
5
7
  trailer_without_triggers(stream)
8
+ ensure
9
+ Builder.show_warnings = orig_show_warnings
6
10
  end
7
11
 
8
12
  def triggers(stream)
@@ -84,4 +88,4 @@ module HairTrigger
84
88
  end
85
89
  end
86
90
  end
87
- end
91
+ end
@@ -1,5 +1,5 @@
1
1
  module HairTrigger
2
- VERSION = "0.2.6"
2
+ VERSION = "0.2.7"
3
3
 
4
4
  def VERSION.<=>(other)
5
5
  split(/\./).map(&:to_i) <=> other.split(/\./).map(&:to_i)
data/spec/builder_spec.rb CHANGED
@@ -60,6 +60,19 @@ describe "builder" do
60
60
  end
61
61
  end
62
62
 
63
+ describe "groups" do
64
+ it "should allow chained methods" do
65
+ triggers = builder.on(:foos){ |t|
66
+ t.where('bar=1').name('bar'){ 'BAR;' }
67
+ t.where('baz=1').name('baz'){ 'BAZ;' }
68
+ }.triggers
69
+ triggers.map(&:prepare!)
70
+ triggers.map(&:prepared_name).should == ['bar', 'baz']
71
+ triggers.map(&:prepared_where).should == ['bar=1', 'baz=1']
72
+ triggers.map(&:prepared_actions).should == ['BAR;', 'BAZ;']
73
+ end
74
+ end
75
+
63
76
  context "adapter-specific actions" do
64
77
  before(:each) do
65
78
  @adapter = MockAdapter.new("mysql")
@@ -112,6 +125,15 @@ describe "builder" do
112
125
  }.should raise_error
113
126
  end
114
127
 
128
+ it "should warn on explicit subtrigger names and no group name" do
129
+ trigger = builder.on(:foos){ |t|
130
+ t.where('bar=1').name('bar'){ 'BAR;' }
131
+ t.where('baz=1').name('baz'){ 'BAZ;' }
132
+ }
133
+ trigger.warnings.size.should == 1
134
+ trigger.warnings.first.first.should =~ /nested triggers have explicit names/
135
+ end
136
+
115
137
  it "should accept security" do
116
138
  builder.on(:foos).after(:update).security(:definer){ "FOO" }.generate.
117
139
  grep(/DEFINER/).size.should eql(0) # default, so we don't include it
@@ -170,6 +192,15 @@ describe "builder" do
170
192
  trigger.generate.grep(/CREATE.*TRIGGER/).size.should eql(3)
171
193
  end
172
194
 
195
+ it "should warn on an explicit group names and no subtrigger names" do
196
+ trigger = builder.on(:foos).name('foos'){ |t|
197
+ t.where('bar=1'){ 'BAR;' }
198
+ t.where('baz=1'){ 'BAZ;' }
199
+ }
200
+ trigger.warnings.size.should == 1
201
+ trigger.warnings.first.first.should =~ /trigger group has an explicit name/
202
+ end
203
+
173
204
  it "should accept security" do
174
205
  builder.on(:foos).after(:update).security(:invoker){ "FOO" }.generate.
175
206
  grep(/SECURITY/).size.should eql(0) # default, so we don't include it
@@ -251,6 +282,15 @@ describe "builder" do
251
282
  trigger.generate.grep(/CREATE.*TRIGGER/).size.should eql(3)
252
283
  end
253
284
 
285
+ it "should warn on an explicit group names and no subtrigger names" do
286
+ trigger = builder.on(:foos).name('foos'){ |t|
287
+ t.where('bar=1'){ 'BAR;' }
288
+ t.where('baz=1'){ 'BAZ;' }
289
+ }
290
+ trigger.warnings.size.should == 1
291
+ trigger.warnings.first.first.should =~ /trigger group has an explicit name/
292
+ end
293
+
254
294
  it "should reject security" do
255
295
  lambda {
256
296
  builder.on(:foos).after(:update).security(:definer){ "FOO" }.generate
@@ -6,9 +6,9 @@ require 'spec_helper'
6
6
 
7
7
  describe "migrations" do
8
8
  include_context "hairtrigger utils"
9
+ let(:adapter) { :sqlite3 }
9
10
 
10
11
  describe "migrations_current?" do
11
- let(:adapter) { :sqlite3 }
12
12
 
13
13
  it "should return false if there are pending model triggers" do
14
14
  reset_tmp(:migration_glob => "*initial_tables*")
@@ -37,4 +37,24 @@ describe "migrations" do
37
37
  HairTrigger.should be_migrations_current
38
38
  end
39
39
  end
40
+
41
+ describe "current_triggers" do
42
+ it "should be inferred from self.up methods" do
43
+ reset_tmp(:migration_glob => "20110331212*")
44
+ initialize_db
45
+
46
+ migrations = HairTrigger.current_migrations
47
+ migrations.size.should == 1
48
+ migrations[0][1].prepared_name.should == "users_after_insert_row_when_new_name_bob__tr"
49
+ end
50
+
51
+ it "should not be inferred from change methods" do
52
+ reset_tmp(:migration_glob => "*manual*")
53
+ replace_file_contents("tmp/migrations/20110417185102_manual_user_trigger.rb", "def up", "def change")
54
+ initialize_db
55
+
56
+ migrations = HairTrigger.current_migrations
57
+ migrations.size.should == 0
58
+ end
59
+ end
40
60
  end
metadata CHANGED
@@ -1,172 +1,167 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: hairtrigger
3
- version: !ruby/object:Gem::Version
4
- hash: 27
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.7
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 2
9
- - 6
10
- version: 0.2.6
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Jon Jensen
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2014-03-25 00:00:00 -06:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2014-04-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: activerecord
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 5
30
- segments:
31
- - 2
32
- - 3
33
- version: "2.3"
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '2.3'
34
22
  type: :runtime
35
- version_requirements: *id001
36
- - !ruby/object:Gem::Dependency
37
- name: ruby_parser
38
23
  prerelease: false
39
- requirement: &id002 !ruby/object:Gem::Requirement
40
- none: false
41
- requirements:
42
- - - ">="
43
- - !ruby/object:Gem::Version
44
- hash: 13
45
- segments:
46
- - 3
47
- - 5
48
- version: "3.5"
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '2.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: ruby_parser
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '3.5'
49
38
  type: :runtime
50
- version_requirements: *id002
51
- - !ruby/object:Gem::Dependency
52
- name: ruby2ruby
53
39
  prerelease: false
54
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '3.5'
46
+ - !ruby/object:Gem::Dependency
47
+ name: ruby2ruby
48
+ requirement: !ruby/object:Gem::Requirement
55
49
  none: false
56
- requirements:
50
+ requirements:
57
51
  - - ~>
58
- - !ruby/object:Gem::Version
59
- hash: 3
60
- segments:
61
- - 2
62
- - 0
63
- - 6
52
+ - !ruby/object:Gem::Version
64
53
  version: 2.0.6
65
54
  type: :runtime
66
- version_requirements: *id003
67
- - !ruby/object:Gem::Dependency
68
- name: rake
69
55
  prerelease: false
70
- requirement: &id004 !ruby/object:Gem::Requirement
71
- none: false
72
- requirements:
73
- - - ">="
74
- - !ruby/object:Gem::Version
75
- hash: 3
76
- segments:
77
- - 0
78
- version: "0"
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 2.0.6
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
79
70
  type: :development
80
- version_requirements: *id004
81
- - !ruby/object:Gem::Dependency
82
- name: rspec
83
71
  prerelease: false
84
- requirement: &id005 !ruby/object:Gem::Requirement
72
+ version_requirements: !ruby/object:Gem::Requirement
85
73
  none: false
86
- requirements:
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
79
+ name: rspec
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
87
83
  - - ~>
88
- - !ruby/object:Gem::Version
89
- hash: 63
90
- segments:
91
- - 2
92
- - 12
93
- - 0
84
+ - !ruby/object:Gem::Version
94
85
  version: 2.12.0
95
86
  type: :development
96
- version_requirements: *id005
97
- - !ruby/object:Gem::Dependency
98
- name: mysql
99
87
  prerelease: false
100
- requirement: &id006 !ruby/object:Gem::Requirement
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 2.12.0
94
+ - !ruby/object:Gem::Dependency
95
+ name: mysql
96
+ requirement: !ruby/object:Gem::Requirement
101
97
  none: false
102
- requirements:
98
+ requirements:
103
99
  - - ~>
104
- - !ruby/object:Gem::Version
105
- hash: 41
106
- segments:
107
- - 2
108
- - 9
109
- - 1
100
+ - !ruby/object:Gem::Version
110
101
  version: 2.9.1
111
102
  type: :development
112
- version_requirements: *id006
113
- - !ruby/object:Gem::Dependency
114
- name: mysql2
115
103
  prerelease: false
116
- requirement: &id007 !ruby/object:Gem::Requirement
117
- none: false
118
- requirements:
119
- - - ">="
120
- - !ruby/object:Gem::Version
121
- hash: 5
122
- segments:
123
- - 0
124
- - 3
125
- - 11
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 2.9.1
110
+ - !ruby/object:Gem::Dependency
111
+ name: mysql2
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
126
117
  version: 0.3.11
127
118
  type: :development
128
- version_requirements: *id007
129
- - !ruby/object:Gem::Dependency
130
- name: pg
131
119
  prerelease: false
132
- requirement: &id008 !ruby/object:Gem::Requirement
133
- none: false
134
- requirements:
135
- - - ">="
136
- - !ruby/object:Gem::Version
137
- hash: 33
138
- segments:
139
- - 0
140
- - 15
141
- - 1
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: 0.3.11
126
+ - !ruby/object:Gem::Dependency
127
+ name: pg
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
142
133
  version: 0.15.1
143
134
  type: :development
144
- version_requirements: *id008
145
- - !ruby/object:Gem::Dependency
146
- name: sqlite3
147
135
  prerelease: false
148
- requirement: &id009 !ruby/object:Gem::Requirement
149
- none: false
150
- requirements:
151
- - - ">="
152
- - !ruby/object:Gem::Version
153
- hash: 21
154
- segments:
155
- - 1
156
- - 3
157
- - 7
136
+ version_requirements: !ruby/object:Gem::Requirement
137
+ none: false
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: 0.15.1
142
+ - !ruby/object:Gem::Dependency
143
+ name: sqlite3
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
158
149
  version: 1.3.7
159
150
  type: :development
160
- version_requirements: *id009
161
- description: allows you to declare database triggers in ruby in your models, and then generate appropriate migrations as they change
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: 1.3.7
158
+ description: allows you to declare database triggers in ruby in your models, and then
159
+ generate appropriate migrations as they change
162
160
  email: jenseng@gmail.com
163
161
  executables: []
164
-
165
162
  extensions: []
166
-
167
163
  extra_rdoc_files: []
168
-
169
- files:
164
+ files:
170
165
  - LICENSE.txt
171
166
  - Rakefile
172
167
  - README.md
@@ -193,43 +188,30 @@ files:
193
188
  - spec/models/user.rb
194
189
  - spec/schema_dumper_spec.rb
195
190
  - spec/spec_helper.rb
196
- has_rdoc: true
197
191
  homepage: http://github.com/jenseng/hair_trigger
198
- licenses:
192
+ licenses:
199
193
  - MIT
200
194
  post_install_message:
201
195
  rdoc_options: []
202
-
203
- require_paths:
196
+ require_paths:
204
197
  - lib
205
- required_ruby_version: !ruby/object:Gem::Requirement
198
+ required_ruby_version: !ruby/object:Gem::Requirement
206
199
  none: false
207
- requirements:
208
- - - ">="
209
- - !ruby/object:Gem::Version
210
- hash: 57
211
- segments:
212
- - 1
213
- - 8
214
- - 7
200
+ requirements:
201
+ - - ! '>='
202
+ - !ruby/object:Gem::Version
215
203
  version: 1.8.7
216
- required_rubygems_version: !ruby/object:Gem::Requirement
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
217
205
  none: false
218
- requirements:
219
- - - ">="
220
- - !ruby/object:Gem::Version
221
- hash: 17
222
- segments:
223
- - 1
224
- - 3
225
- - 5
206
+ requirements:
207
+ - - ! '>='
208
+ - !ruby/object:Gem::Version
226
209
  version: 1.3.5
227
210
  requirements: []
228
-
229
211
  rubyforge_project:
230
- rubygems_version: 1.6.2
212
+ rubygems_version: 1.8.23
231
213
  signing_key:
232
214
  specification_version: 3
233
215
  summary: easy database triggers for active record
234
216
  test_files: []
235
-
217
+ has_rdoc: