hairtrigger 0.2.19 → 0.2.24

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f42f7d04b773f6a0ce1f5acc86e90746f35322b1
4
- data.tar.gz: d05ccf70ece346e5e73ed4433e11dc678c0bd6e9
3
+ metadata.gz: b3a4b255f8184decc442a9c455f5b8a5a5c9bd48
4
+ data.tar.gz: b6c202c7328de121c67161cc4d31d83926076044
5
5
  SHA512:
6
- metadata.gz: 5d78e2251de79e05fdd17f1194b7f3ac7afd1711bd5cd5a40fd0205f39f4f884ca63839152e45d3a70bc60c50f2210fef4a9a6ff72e736ba05c69f0d78bda570
7
- data.tar.gz: 970c56031d52a6ad9f355e97dcad81f877ccf806a9bc4a7d6d1a659b5a5e0c04cc9505251be5982a126e625e227859c99217c3ef140678a889915a0a8f806ca2
6
+ metadata.gz: 5eb6f48db749f2841ee9a0b986dbaf9cf2d93f48f687822e8a6dda52c90e45165fba783510e7fb1e5ec8a490ce4a6dd58df5f2ebd04567e3d2839f87ef82815f
7
+ data.tar.gz: c8eebfc8a7a45d4987f1d6ea5281a06c333a4eee929830a73a78521c442983b1743f14a4f677fb31de9d4a7ce6b144f67000f84cd7c068d08160ef260bb815cf
data/README.md CHANGED
@@ -7,8 +7,15 @@ and a simple rake task does all the dirty work for you.
7
7
 
8
8
  ## Installation
9
9
 
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)
10
+ HairTrigger works with Rails 5.0 onwards. Add the following line to your Gemfile:
11
+
12
+ ```ruby
13
+ gem 'hairtrigger'
14
+ ```
15
+
16
+ Then run `bundle install`
17
+
18
+ For older versions of Rails check the last [0.2 release](https://github.com/jenseng/hair_trigger/tree/v0.2.21)
12
19
 
13
20
  ## Usage
14
21
 
@@ -248,7 +255,7 @@ create.
248
255
 
249
256
  ## Warnings and Errors
250
257
 
251
- There are a couple classes of errors: declaration errors and generation
258
+ There are a couple classes of errors: declaration errors and generation
252
259
  errors/warnings.
253
260
 
254
261
  Declaration errors happen if your trigger declaration is obviously wrong, and
@@ -313,10 +320,26 @@ existing trigger if you wish to redefine it.
313
320
  * Manual `create_trigger` statements have some gotchas. See the section
314
321
  "Manual triggers and :compatibility"
315
322
 
323
+ ## Contributing
324
+
325
+ Contributions welcome! I don't write much Ruby these days 😢 (and haven't used this
326
+ gem in years 😬) but am happy to take contributions. If I'm slow to respond, don't
327
+ hesitate to @ me repeatedly, sometimes those github notifications slip through
328
+ the cracks. 😆.
329
+
330
+ If you want to add a feature/bugfix, you can rely on Travis to run the tests, but
331
+ do also run them locally (especially if you are changing supported railses/etc).
332
+ HairTrigger uses [appraisal](https://github.com/thoughtbot/appraisal) to manage all
333
+ that w/ automagical gemfiles. So the tl;dr when testing locally is:
334
+
335
+ 1. make sure you have mysql and postgres installed (homebrew or whatever)
336
+ 2. `bundle exec appraisal install` -- get all the dependencies
337
+ 3. `bundle exec appraisal rake` -- run the specs every which way
338
+
316
339
  ## Compatibility
317
340
 
318
- * Ruby 1.8.7+
319
- * Rails 2.3+
341
+ * Ruby 2.3.0+
342
+ * Rails 5.0+
320
343
  * PostgreSQL 8.0+
321
344
  * MySQL 5.0.10+
322
345
  * SQLite 3.3.8+
@@ -325,4 +348,4 @@ existing trigger if you wish to redefine it.
325
348
 
326
349
  ## Copyright
327
350
 
328
- Copyright (c) 2011-2015 Jon Jensen. See LICENSE.txt for further details.
351
+ Copyright (c) 2011-2021 Jon Jensen. See LICENSE.txt for further details.
@@ -1,4 +1,5 @@
1
1
  require 'ostruct'
2
+ require 'fileutils'
2
3
  require 'active_record'
3
4
  require 'hair_trigger/base'
4
5
  require 'hair_trigger/migrator'
@@ -21,7 +22,7 @@ module HairTrigger
21
22
  end
22
23
 
23
24
  def models
24
- if defined?(Rails) && Rails::VERSION::MAJOR > 2
25
+ if defined?(Rails)
25
26
  Rails.application.eager_load!
26
27
  else
27
28
  Dir[model_path + '/*rb'].each do |model|
@@ -34,16 +35,24 @@ module HairTrigger
34
35
  end
35
36
  end
36
37
  end
37
- ActiveRecord::VERSION::STRING < "3.0." ?
38
- ActiveRecord::Base.send(:subclasses) :
39
- ActiveRecord::Base.descendants
38
+ ActiveRecord::Base.descendants
40
39
  end
41
40
 
42
41
  def migrator
43
- migrations = ActiveRecord::VERSION::STRING >= "4.0." ?
44
- ActiveRecord::Migrator.migrations(migration_path) :
45
- migration_path
46
- ActiveRecord::Migrator.new(:up, migrations)
42
+ version = ActiveRecord::VERSION::STRING
43
+ if version >= "6.0."
44
+ migrations = ActiveRecord::MigrationContext.new(migration_path, ActiveRecord::SchemaMigration).migrations
45
+ elsif version >= "5.2."
46
+ migrations = ActiveRecord::MigrationContext.new(migration_path).migrations
47
+ else # version >= "4.0."
48
+ migrations = ActiveRecord::Migrator.migrations(migration_path)
49
+ end
50
+
51
+ if version >= "6.0."
52
+ ActiveRecord::Migrator.new(:up, migrations, ActiveRecord::SchemaMigration)
53
+ else
54
+ ActiveRecord::Migrator.new(:up, migrations)
55
+ end
47
56
  end
48
57
 
49
58
  def current_migrations(options = {})
@@ -52,7 +61,7 @@ module HairTrigger
52
61
  options[:schema_rb_first] = true
53
62
  options[:skip_pending_migrations] = true
54
63
  end
55
-
64
+
56
65
  # if we're in a db:schema:dump task (explict or kicked off by db:migrate),
57
66
  # we evaluate the previous schema.rb (if it exists), and then all applied
58
67
  # migrations in order (even ones older than schema.rb). this ensures we
@@ -69,7 +78,7 @@ module HairTrigger
69
78
  triggers = MigrationReader.get_triggers(migration, options)
70
79
  migrations << [migration, triggers] unless triggers.empty?
71
80
  end
72
-
81
+
73
82
  if previous_schema = (options.has_key?(:previous_schema) ? options[:previous_schema] : File.exist?(schema_rb_path) && File.read(schema_rb_path))
74
83
  base_triggers = MigrationReader.get_triggers(previous_schema, options)
75
84
  unless base_triggers.empty?
@@ -77,9 +86,9 @@ module HairTrigger
77
86
  migrations.unshift [OpenStruct.new({:version => version}), base_triggers]
78
87
  end
79
88
  end
80
-
89
+
81
90
  migrations = migrations.sort_by{|(migration, triggers)| migration.version} unless options[:schema_rb_first]
82
-
91
+
83
92
  all_builders = []
84
93
  migrations.each do |(migration, triggers)|
85
94
  triggers.each do |new_trigger|
@@ -90,7 +99,7 @@ module HairTrigger
90
99
  all_builders << [migration.name, new_trigger] unless new_trigger.options[:drop]
91
100
  end
92
101
  end
93
-
102
+
94
103
  all_builders
95
104
  end
96
105
 
@@ -101,27 +110,27 @@ module HairTrigger
101
110
  def generate_migration(silent = false)
102
111
  begin
103
112
  canonical_triggers = current_triggers
104
- rescue
113
+ rescue
105
114
  $stderr.puts $!
106
115
  exit 1
107
116
  end
108
-
117
+
109
118
  migrations = current_migrations
110
119
  migration_names = migrations.map(&:first)
111
120
  existing_triggers = migrations.map(&:last)
112
-
121
+
113
122
  up_drop_triggers = []
114
123
  up_create_triggers = []
115
124
  down_drop_triggers = []
116
125
  down_create_triggers = []
117
-
126
+
118
127
  # see which triggers need to be dropped
119
128
  existing_triggers.each do |existing|
120
129
  next if canonical_triggers.any?{ |t| t.prepared_name == existing.prepared_name }
121
130
  up_drop_triggers.concat existing.drop_triggers
122
131
  down_create_triggers << existing
123
132
  end
124
-
133
+
125
134
  # see which triggers need to be added/replaced
126
135
  (canonical_triggers - existing_triggers).each do |new_trigger|
127
136
  up_create_triggers << new_trigger
@@ -134,28 +143,28 @@ module HairTrigger
134
143
  down_create_triggers << existing
135
144
  end
136
145
  end
137
-
146
+
138
147
  return if up_drop_triggers.empty? && up_create_triggers.empty?
139
148
 
140
149
  migration_name = infer_migration_name(migration_names, up_create_triggers, up_drop_triggers)
141
150
  migration_version = infer_migration_version(migration_name)
142
151
  file_name = migration_path + '/' + migration_version + "_" + migration_name.underscore + ".rb"
143
- prefix = ActiveRecord::VERSION::STRING < "3.1." ? "self." : ""
144
- File.open(file_name, "w"){ |f| f.write <<-MIGRATION }
152
+ FileUtils.mkdir_p migration_path
153
+ File.open(file_name, "w") { |f| f.write <<-RUBY }
145
154
  # This migration was auto-generated via `rake db:generate_trigger_migration'.
146
155
  # While you can edit this file, any changes you make to the definitions here
147
156
  # will be undone by the next auto-generated trigger migration.
148
157
 
149
- class #{migration_name} < ActiveRecord::Migration
150
- def #{prefix}up
158
+ class #{migration_name} < ActiveRecord::Migration[#{ActiveRecord::Migration.current_version}]
159
+ def up
151
160
  #{(up_drop_triggers + up_create_triggers).map{ |t| t.to_ruby(' ') }.join("\n\n").lstrip}
152
161
  end
153
162
 
154
- def #{prefix}down
163
+ def down
155
164
  #{(down_drop_triggers + down_create_triggers).map{ |t| t.to_ruby(' ') }.join("\n\n").lstrip}
156
165
  end
157
166
  end
158
- MIGRATION
167
+ RUBY
159
168
  file_name
160
169
  end
161
170
 
@@ -217,11 +226,9 @@ end
217
226
  end
218
227
  end
219
228
 
220
- ActiveRecord::Base.send :extend, HairTrigger::Base
221
- if ActiveRecord::VERSION::STRING < "4.1."
222
- ActiveRecord::Migrator.send :extend, HairTrigger::Migrator
223
- else
229
+ ActiveSupport.on_load(:active_record) do
230
+ ActiveRecord::Base.send :extend, HairTrigger::Base
224
231
  ActiveRecord::Migration.send :include, HairTrigger::Migrator
232
+ ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval { include HairTrigger::Adapter }
233
+ ActiveRecord::SchemaDumper.class_eval { include HairTrigger::SchemaDumper }
225
234
  end
226
- ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval { include HairTrigger::Adapter }
227
- ActiveRecord::SchemaDumper.class_eval { include HairTrigger::SchemaDumper }
@@ -137,22 +137,22 @@ module HairTrigger
137
137
  methods.each do |method|
138
138
  class_eval <<-METHOD, __FILE__, __LINE__ + 1
139
139
  alias #{method}_orig #{method}
140
- def #{method}(*args)
140
+ def #{method}(*args, &block)
141
141
  @chained_calls << :#{method}
142
142
  if @triggers || @trigger_group
143
143
  @errors << ["mysql doesn't support #{method} within a trigger group", :mysql] unless [:name, :where, :all, :of].include?(:#{method})
144
144
  end
145
- set_#{method}(*args, &(block_given? ? Proc.new : nil))
145
+ set_#{method}(*args, &(block_given? ? block : nil))
146
146
  end
147
- def set_#{method}(*args)
147
+ def set_#{method}(*args, &block)
148
148
  if @triggers # i.e. each time we say t.something within a trigger group block
149
149
  @chained_calls.pop # the subtrigger will get this, we don't need it
150
150
  @chained_calls = @chained_calls.uniq
151
151
  @triggers << trigger = clone
152
- trigger.#{method}(*args, &(block_given? ? Proc.new : nil))
152
+ trigger.#{method}(*args, &(block_given? ? block : nil))
153
153
  else
154
- #{method}_orig(*args)
155
- maybe_execute(&Proc.new) if block_given?
154
+ #{method}_orig(*args, &block)
155
+ maybe_execute(&block) if block_given?
156
156
  self
157
157
  end
158
158
  end
@@ -335,10 +335,11 @@ module HairTrigger
335
335
  block.call(self)
336
336
  raise DeclarationError, "trigger group did not define any triggers" if @triggers.empty?
337
337
  else
338
- @actions = block.call
339
- (@actions.is_a?(Hash) ? @actions.values : [@actions]).each do |actions|
340
- actions.sub!(/(\s*)\z/, ';\1') if actions && actions !~ /;\s*\z/
341
- end
338
+ @actions =
339
+ case (actions = block.call)
340
+ when Hash then actions.map { |key, action| [key, ensure_semicolon(action)] }.to_h
341
+ else ensure_semicolon(actions)
342
+ end
342
343
  end
343
344
  # only the top-most block actually executes
344
345
  if !@trigger_group
@@ -350,6 +351,10 @@ module HairTrigger
350
351
  self
351
352
  end
352
353
 
354
+ def ensure_semicolon(action)
355
+ action && action !~ /;\s*\z/ ? action.sub(/(\s*)\z/, ';\1') : action
356
+ end
357
+
353
358
  def validate_names!
354
359
  subtriggers = all_triggers(false)
355
360
  named_subtriggers = subtriggers.select{ |t| t.options[:name] }
@@ -427,7 +432,7 @@ END;
427
432
  raise GenerationError, "declare cannot be used in conjunction with nowrap" if options[:nowrap] && options[:declare]
428
433
  raise GenerationError, "security cannot be used in conjunction with nowrap" if options[:nowrap] && options[:security]
429
434
  raise GenerationError, "where can only be used in conjunction with nowrap on postgres 9.0 and greater" if options[:nowrap] && prepared_where && db_version < 90000
430
- raise GenerationError, "of can only be used in conjunction with nowrap on postgres 9.1 and greater" if options[:nowrap] && options[:of] && db_version < 91000
435
+ raise GenerationError, "of can only be used in conjunction with nowrap on postgres 9.1 and greater" if options[:nowrap] && options[:of] && db_version < 90100
431
436
 
432
437
  sql = ''
433
438
 
@@ -1,23 +1,25 @@
1
1
  module HairTrigger
2
2
  module Migrator
3
- def proper_table_name_with_hash_awareness(*args)
4
- name = args.first
5
- return name if name.is_a?(Hash)
6
- proper_table_name_without_hash_awareness(*args)
7
- end
8
-
9
3
  class << self
4
+ module ProperTableNameWithHashAwarenessSupport
5
+ def proper_table_name(*args)
6
+ name = args.first
7
+ return name if name.is_a?(Hash)
8
+ super
9
+ end
10
+ end
11
+
10
12
  def extended(base)
11
13
  base.class_eval do
12
14
  class << self
13
- alias_method_chain :proper_table_name, :hash_awareness
15
+ prepend ProperTableNameWithHashAwarenessSupport
14
16
  end
15
17
  end
16
18
  end
17
19
 
18
20
  def included(base)
19
21
  base.instance_eval do
20
- alias_method_chain :proper_table_name, :hash_awareness
22
+ prepend ProperTableNameWithHashAwarenessSupport
21
23
  end
22
24
  end
23
25
  end
@@ -1,13 +1,14 @@
1
1
  module HairTrigger
2
2
  module SchemaDumper
3
-
4
- def trailer_with_triggers(stream)
5
- orig_show_warnings = Builder.show_warnings
6
- Builder.show_warnings = false # we already show them when running the migration
7
- triggers(stream)
8
- trailer_without_triggers(stream)
9
- ensure
10
- Builder.show_warnings = orig_show_warnings
3
+ module TrailerWithTriggersSupport
4
+ def trailer(stream)
5
+ orig_show_warnings = Builder.show_warnings
6
+ Builder.show_warnings = false # we already show them when running the migration
7
+ triggers(stream)
8
+ super
9
+ ensure
10
+ Builder.show_warnings = orig_show_warnings
11
+ end
11
12
  end
12
13
 
13
14
  def triggers(stream)
@@ -54,7 +55,7 @@ module HairTrigger
54
55
  stream.puts " # no candidate create_trigger statement could be found, creating an adapter-specific one"
55
56
  end
56
57
  if definition =~ /\n/
57
- stream.print " execute(<<-TRIGGERSQL)\n#{definition.rstrip}\n TRIGGERSQL\n\n"
58
+ stream.print " execute(<<-SQL)\n#{definition.rstrip}\n SQL\n\n"
58
59
  else
59
60
  stream.print " execute(#{definition.inspect})\n\n"
60
61
  end
@@ -66,7 +67,7 @@ module HairTrigger
66
67
  def normalize_trigger(name, definition, type)
67
68
  @adapter_name = @connection.adapter_name.downcase.to_sym
68
69
 
69
- return definition unless @adapter_name == :postgresql
70
+ return definition unless @adapter_name == :postgresql || @adapter_name == :postgis
70
71
  # because postgres does not preserve the original CREATE TRIGGER/
71
72
  # FUNCTION statements, its decompiled reconstruction will not match
72
73
  # ours. we work around it by creating our generated trigger/function,
@@ -97,10 +98,9 @@ module HairTrigger
97
98
 
98
99
  def self.included(base)
99
100
  base.class_eval do
100
- alias_method_chain :trailer, :triggers
101
- class << self
102
- attr_accessor :previous_schema
103
- end
101
+ prepend TrailerWithTriggersSupport
102
+
103
+ class_attribute :previous_schema
104
104
  end
105
105
  end
106
106
  end
@@ -1,5 +1,5 @@
1
1
  module HairTrigger
2
- VERSION = "0.2.19"
2
+ VERSION = "0.2.24"
3
3
 
4
4
  def VERSION.<=>(other)
5
5
  split(/\./).map(&:to_i) <=> other.split(/\./).map(&:to_i)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hairtrigger
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.19
4
+ version: 0.2.24
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Jensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-26 00:00:00.000000000 Z
11
+ date: 2021-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,42 +16,48 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '2.3'
19
+ version: '5.0'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '7'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - ">="
25
28
  - !ruby/object:Gem::Version
26
- version: '2.3'
29
+ version: '5.0'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '7'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: ruby_parser
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - "~>"
32
38
  - !ruby/object:Gem::Version
33
- version: '3.8'
39
+ version: '3.10'
34
40
  type: :runtime
35
41
  prerelease: false
36
42
  version_requirements: !ruby/object:Gem::Requirement
37
43
  requirements:
38
44
  - - "~>"
39
45
  - !ruby/object:Gem::Version
40
- version: '3.8'
46
+ version: '3.10'
41
47
  - !ruby/object:Gem::Dependency
42
48
  name: ruby2ruby
43
49
  requirement: !ruby/object:Gem::Requirement
44
50
  requirements:
45
51
  - - "~>"
46
52
  - !ruby/object:Gem::Version
47
- version: '2.3'
53
+ version: '2.4'
48
54
  type: :runtime
49
55
  prerelease: false
50
56
  version_requirements: !ruby/object:Gem::Requirement
51
57
  requirements:
52
58
  - - "~>"
53
59
  - !ruby/object:Gem::Version
54
- version: '2.3'
60
+ version: '2.4'
55
61
  description: allows you to declare database triggers in ruby in your models, and then
56
62
  generate appropriate migrations as they change
57
63
  email: jenseng@gmail.com
@@ -73,19 +79,6 @@ files:
73
79
  - lib/hair_trigger/version.rb
74
80
  - lib/hairtrigger.rb
75
81
  - lib/tasks/hair_trigger.rake
76
- - spec/adapter_spec.rb
77
- - spec/builder_spec.rb
78
- - spec/migrations-pre-3.1/20110331212003_initial_tables.rb
79
- - spec/migrations-pre-3.1/20110331212631_user_trigger.rb
80
- - spec/migrations-pre-3.1/20110417185102_manual_user_trigger.rb
81
- - spec/migrations/20110331212003_initial_tables.rb
82
- - spec/migrations/20110331212631_user_trigger.rb
83
- - spec/migrations/20110417185102_manual_user_trigger.rb
84
- - spec/migrations_spec.rb
85
- - spec/models/group.rb
86
- - spec/models/user.rb
87
- - spec/schema_dumper_spec.rb
88
- - spec/spec_helper.rb
89
82
  homepage: http://github.com/jenseng/hair_trigger
90
83
  licenses:
91
84
  - MIT
@@ -98,15 +91,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
98
91
  requirements:
99
92
  - - ">="
100
93
  - !ruby/object:Gem::Version
101
- version: 1.8.7
94
+ version: 2.3.0
102
95
  required_rubygems_version: !ruby/object:Gem::Requirement
103
96
  requirements:
104
97
  - - ">="
105
98
  - !ruby/object:Gem::Version
106
- version: 1.3.5
99
+ version: '0'
107
100
  requirements: []
108
101
  rubyforge_project:
109
- rubygems_version: 2.5.1
102
+ rubygems_version: 2.5.2.3
110
103
  signing_key:
111
104
  specification_version: 4
112
105
  summary: easy database triggers for active record