wagons 0.7.0 → 0.8.0

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
  SHA256:
3
- metadata.gz: 3d06295f19bd1963830bd47006676c4b25eb2b1e7b30af0f8c2302996b129493
4
- data.tar.gz: d3c66601cc2869001432ae9877cbd03dfd6a68f9685aa47ab929a3b36023dcef
3
+ metadata.gz: 115a339a7bcdac6dcaa1421a9c10b721ccbe58274b02fd88913c9a0c6c012bc1
4
+ data.tar.gz: 8b75fa6188d5742edc1468d07b07ecc9b7c4464c4f42eb52f4a12bf30af24c4c
5
5
  SHA512:
6
- metadata.gz: bb293faaa5f7639c22dea5b78a98b202936ad6dd5fe6016c7215b81866861c9eb23a81a733e2dffc27ce09d1ebd7459f000a33dd73913e94633a4d0b96ad245a
7
- data.tar.gz: ac080f11d0a70f91755e510f365a9c36bfec28e2918fd167edf58524f40834c52b0fae01bcb8dd44b1e1bce8ca7abc50bd96e877220ffbd454b80a9e4aaac076
6
+ metadata.gz: bb5f39ce863e8540db973fcb4882b35e8e3734edc380e58df0b72ed9da53412081b94389782ac6dccb431b204f400470bb88aeabecea37644e49b78f8acd71e0
7
+ data.tar.gz: 1f6330feb1ceaf5bf001c126a95dd661432e4ac96cf170031e26db94da183a3955406adc0491d65ce480057c2137c58bdf5971e0608ed8e62d1c9bc856a1bdde
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2012 Pascal Zumkehr
1
+ Copyright 2012-2023 Pascal Zumkehr, Puzzle ITC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # Here Be Wagons
2
+
3
+ [![Build Status](https://github.com/codez/wagons/actions/workflows/build.yml/badge.svg)](https://github.com/codez/wagons/actions/workflows/build.yml)
4
+ [![Code Climate](https://api.codeclimate.com/v1/badges/32a0d860544681cf718c/maintainability)](https://codeclimate.com/github/codez/wagons/maintainability)
5
+
6
+ Wagons are extensions to your application train running on Rails. You can see them as plugins that
7
+ extend the behavior of your specific Rails application. This framework makes it easy to create and
8
+ manage them.
9
+
10
+ First of all, wagons are basically [Rails Engines](http://api.rubyonrails.org/classes/Rails/Engine.html),
11
+ so make sure you are familiar with them. Wagons provide a handful of additions so your wagon
12
+ engines actually know your application.
13
+
14
+ Wagons differ from engines in a few points:
15
+
16
+ - Wagons extend your application, engines extend Rails.
17
+ - Wagon migrations are kept separately from your application's migrations to enable easy addition and removal of wagons.
18
+ - When developing and testing, wagons use the main application instead of a dummy application.
19
+
20
+ ## Setup
21
+
22
+ As always, add this declaration to your application's Gemfile:
23
+
24
+ gem 'wagons'
25
+
26
+ Now you are ready for your first wagon. Generate it with
27
+
28
+ rails generate wagon [name]
29
+
30
+ This creates the structure of your wagon in `vendor/wagons/[name]`. In there, you find the file `lib/[name]/wagon.rb`,
31
+ which defines the `Rails::Engine` and includes the `Wagon` module. Here, you may also extend your application
32
+ classes in a `config.to_prepare` block.
33
+
34
+ In order to load wagons with the application, an entry in the `Gemfile` would be sufficient.
35
+ To keep things flexible, wagons come with an additional file `Wagonfile`. Generate one for development purposes with:
36
+
37
+ rake wagon:file
38
+
39
+ This will include all wagons found in `vendor/wagons` in development mode.
40
+ Do not check `Wagonfile` into source control. In your deployments, you might want to have different entries in there.
41
+
42
+ Once your wagon is ready to ship, a gem can be built with `rake build`. The name of a wagon gem must always start
43
+ with the application name, followed with an underscore and the actual name of the wagon. In production, you may
44
+ simply install the wagon gem and explicitly add a declaration to your `Wagonfile`.
45
+
46
+ If your wagon contains migrations and probably seed data, update your database with
47
+
48
+ rake wagon:setup WAGON=[name]
49
+
50
+ Leave off the `WAGON` parameter to setup all wagons in your `Wagonfile`. This should not interfere with wagons that are
51
+ already set up. Migrations are only run if they are not loaded yet, as usual.
52
+
53
+ ## Extending your application with a wagon
54
+
55
+ Ruby and Rails provide all the magic required to extend your application from within a wagon.
56
+
57
+ To add new models, controllers or views, simply create them in the `app` directory of your wagon, as you would in a regular engine.
58
+
59
+ To extend existing models and controllers, you may create modules with the required functionality.
60
+ Include them into your application classes in a `config.to_prepare` block in `lib/[wagon_name]/wagon.rb`.
61
+
62
+ To extend views, wagons provides a simple view helper that looks for partials in all view paths. Any template that
63
+ might be extended by a wagon can include a call like this:
64
+
65
+ <%= render_extensions :details %>
66
+
67
+ Any partials living in an equally named subfolder as the calling template and starting with the given key are rendered at this place.
68
+
69
+ ## Wagon dependencies
70
+
71
+ Wagons may depend on each other and/or have certain requirements on their load order. To make sure something
72
+ is loaded before the current wagon, add a `require '[app_name]_[other_wagon]'` on top of the
73
+ `lib/[app_name]_[current_wagon].rb` file. For development dependencies, there is an extra `require_optional`
74
+ method that will not raise a `LoadError` if the dependency is not found.
75
+
76
+ To control that the main application actually supports a certain wagon, an application version may be defined
77
+ so wagons can define a requirement. The application version can be set in an initializer. Create it with:
78
+
79
+ rake wagon:app_version
80
+
81
+ Besides setting the version, this initializer will check all loaded wagons for their application requirement
82
+ and raise errors if one is not met. In `lib/[wagon_name]/wagon.rb` the requirement may be defined, e.g.:
83
+
84
+ app_requirement '>= 1.0'
85
+
86
+ The syntax follows the Ruby gem version and requirements.
87
+
88
+ ## Seed Data
89
+
90
+ Wagons integrates [Seed Fu](https://github.com/mbleigh/seed-fu) for seed data. All seed data from the application
91
+ is also available in wagon tests, as long as no fixture files overwrite the corresponding tables.
92
+
93
+ Wagons may come with their own seed data as well. Simply put it into `db/fixtures[/environment]`. To allow for
94
+ an automatic removal of wagons, [Seed Fu-ndo](https://github.com/codez/seed-fu-ndo) is able to record
95
+ seed file instructions and destroy all entries that exist in the database. Just make sure that you only use
96
+ the `seed` and `seed_once` methods in these files, or the unseed may not work correctly.
97
+
98
+ ## Beware
99
+
100
+ There are a few other things that work differently with wagons:
101
+
102
+ ### Schema & Migrations
103
+
104
+ Wagons are extensions to your application that may vary between various installations. Wagon tables are added
105
+ and removed as wagons are installed or uninstalled. After you have added a wagon's gem to your production
106
+ `Wagonfile`, run `rake wagon:setup` to run the migrations and load the seed data. Before you remove them
107
+ from `Wagonfile`, run `rake wagon:remove WAGON=to_remove` to eliminate the artifacts from the database first.
108
+
109
+ In this way, the `schema.rb` file must only contain the tables of the application, not of all wagons.
110
+ When you have migrations for your main application and wagons loaded, the schema will not be dumped on
111
+ `db:migrate`. You need to either remove the wagons or reset the database before the schema may be dumped.
112
+ This is (currently) the cost for having arbitrary pluggable application extensions.
113
+
114
+ ### Tests
115
+
116
+ Wagons use your application for tests. This is also true for your application's test database. To get the
117
+ correct setup, `app:db:test:prepare` is extended to run the migration of the current wagon and all its
118
+ dependencies, as well as their seed data. Once the database is set up, single tests may be run with
119
+ the usual `ruby -I test test/my_test.rb` command.
120
+
121
+ The `test_helper.rb` of the main application is included in all wagon tests. Any additions in
122
+ this file are available in wagon tests as well. The only thing wagons need to do is reseting the
123
+ fixture path to the wagon's test fixtures.
124
+
125
+ RSpec works fine with wagons as well. Simply put the heading lines found in `test_helper.rb` into your
126
+ `spec_helper.rb`.
127
+
128
+ ### Gem Bundling
129
+
130
+ Bundler manages application dependencies, with a stress on application. Because wagons live
131
+ inside your application during development, the app's `Gemfile` is included in each wagon's `Gemfile`.
132
+ However, Bundler still keeps a separate `Gemfile.lock` for each wagon, so you have to make sure to keep
133
+ these up to date when you change your main application gems. The gem versions for the wagons should be
134
+ the same as for the application. `rake wagon:bundle:update` is here to help you exactly with that.
135
+ We recommend to NOT check in the Wagon's `Gemfile.lock` file into source control.
136
+
137
+ Unfortunately, adding wagon gems to the `Wagonfile` in production also breaks with Bundler's approach
138
+ of locking down application gems. Because of that, the `--deployment` option cannot be used
139
+ with wagons. If you install your gems from `vendor/cache` into `vendor/bundle` or so,
140
+ you still get most of the benefits of using Bundler, including the guarantee for the very same gem
141
+ versions as used in development.
142
+
143
+ Contributions to this or any other issues are very welcome.
@@ -143,14 +143,12 @@ eval(File.read(wagonfile)) if File.exist?(wagonfile)"
143
143
  task :abort_if_pending_migrations => :environment do
144
144
  paths = wagons.collect(&:migrations_paths).flatten
145
145
 
146
- pending_migrations =
147
- if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0')
148
- context = ActiveRecord::MigrationContext.new(paths)
149
- ActiveRecord::Migrator.new(:up, context.migrations).pending_migrations
150
- else
151
- context = ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration)
152
- ActiveRecord::Migrator.new(:up, context.migrations, ActiveRecord::SchemaMigration).pending_migrations
153
- end
146
+ context = ActiveRecord::MigrationContext.new(paths, ActiveRecord::SchemaMigration)
147
+ pending_migrations = ActiveRecord::Migrator.new(
148
+ :up,
149
+ context.migrations,
150
+ ActiveRecord::SchemaMigration
151
+ ).pending_migrations
154
152
 
155
153
  if pending_migrations.any?
156
154
  puts "You have #{pending_migrations.size} pending migrations:"
@@ -188,12 +186,7 @@ namespace :db do
188
186
  Rake::Task[:'db:_dump'].clear_actions
189
187
 
190
188
  task :_dump do
191
- context =
192
- if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0')
193
- ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths)
194
- else
195
- ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration)
196
- end
189
+ context = ActiveRecord::MigrationContext.new(ActiveRecord::Migrator.migrations_paths, ActiveRecord::SchemaMigration)
197
190
  migrated = Set.new(context.get_all_versions)
198
191
  if migrated.size > context.migrations.size
199
192
  puts "The database schema will not be dumped when there are loaded wagon migrations."
@@ -206,11 +199,15 @@ namespace :db do
206
199
  end
207
200
 
208
201
  task :_dump_rails do
209
- case ActiveRecord::Base.schema_format
202
+ schema_format =
203
+ Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('7.1.0') ?
204
+ ActiveRecord::Base.schema_format : ActiveRecord.schema_format
205
+
206
+ case schema_format
210
207
  when :ruby then Rake::Task["db:schema:dump"].invoke
211
208
  when :sql then Rake::Task["db:structure:dump"].invoke
212
209
  else
213
- raise "unknown schema format #{ActiveRecord::Base.schema_format}"
210
+ raise "unknown schema format #{schema_format}"
214
211
  end
215
212
  Rake::Task[:'db:_dump_rails'].reenable
216
213
  end
@@ -19,16 +19,15 @@ module ActiveRecord
19
19
  private
20
20
 
21
21
  def load_wagon_schema!
22
- Base.clear_all_connections!
22
+ if rails_version_smaller_than('7.1.0')
23
+ Base.clear_all_connections!
24
+ else
25
+ Base.connection_handler.clear_all_connections!
26
+ end
23
27
 
24
28
  # Contrary to the original rails approach (#load_schema_if_pending!),
25
29
  # purge the database first to get rid of all wagon tables.
26
- config =
27
- if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.1.0')
28
- Base.configurations['test']
29
- else
30
- Base.configurations.configs_for(env_name: 'test').first
31
- end
30
+ config = Base.configurations.configs_for(env_name: 'test').first
32
31
  Tasks::DatabaseTasks.purge(config)
33
32
 
34
33
  Base.establish_connection(config)
@@ -39,7 +38,11 @@ module ActiveRecord
39
38
 
40
39
  def load_app_schema(config)
41
40
  Tasks::DatabaseTasks.load_schema(config)
42
- check_pending!
41
+ if rails_version_smaller_than('7.1.0')
42
+ check_pending!
43
+ else
44
+ check_all_pending!
45
+ end
43
46
  end
44
47
 
45
48
  def app_needs_migration?
@@ -52,29 +55,41 @@ module ActiveRecord
52
55
  end
53
56
 
54
57
  def migration_versions_in_db
55
- if Base.connection.table_exists?(SchemaMigration.table_name)
58
+ if schema_migration_table_exists?
56
59
  migration_context.get_all_versions.to_set
57
60
  else
58
61
  [].to_set
59
62
  end
60
63
  end
61
64
 
62
- def migration_context
63
- if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0')
64
- MigrationContext.new(Migrator.migrations_paths)
65
+ def schema_migration_table_exists?
66
+ if rails_version_smaller_than('7.1.0')
67
+ Base.connection.table_exists?(SchemaMigration.table_name)
65
68
  else
69
+ SchemaMigration.new(Base.connection).table_exists?
70
+ end
71
+ end
72
+
73
+ def migration_context
74
+ if rails_version_smaller_than('7.1.0')
66
75
  MigrationContext.new(Migrator.migrations_paths, SchemaMigration)
76
+ else
77
+ MigrationContext.new(Migrator.migrations_paths)
67
78
  end
68
79
  end
69
80
 
70
81
  def maintain_test_schema?
71
- if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('7.0.0')
82
+ if rails_version_smaller_than('7.0.0')
72
83
  ActiveRecord::Base.maintain_test_schema
73
84
  else
74
85
  ActiveRecord.maintain_test_schema
75
86
  end
76
87
  end
77
88
 
89
+ def rails_version_smaller_than(version)
90
+ Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new(version)
91
+ end
92
+
78
93
  end
79
94
  end
80
95
  end
@@ -4,7 +4,11 @@ module ActiveSupport #:nodoc:
4
4
  def self.reset_fixture_path(path)
5
5
  self.fixture_table_names = []
6
6
  self.fixture_class_names = {}
7
- self.fixture_path = path
7
+ if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('7.1.0')
8
+ self.fixture_path = path
9
+ else
10
+ self.fixture_paths = [path]
11
+ end
8
12
  fixtures :all
9
13
  end
10
14
  end
@@ -1,3 +1,3 @@
1
1
  module Wagons
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
data/lib/wagons/wagon.rb CHANGED
@@ -127,10 +127,10 @@ module Wagons
127
127
  end
128
128
 
129
129
  def migration_context
130
- if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('6.0.0')
131
- ActiveRecord::MigrationContext.new(migrations_paths)
132
- else
130
+ if Gem::Version.new(Rails::VERSION::STRING) < Gem::Version.new('7.1.0')
133
131
  ActiveRecord::MigrationContext.new(migrations_paths, ActiveRecord::SchemaMigration)
132
+ else
133
+ ActiveRecord::MigrationContext.new(migrations_paths)
134
134
  end
135
135
  end
136
136
 
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec :path => '../..'
4
4
 
5
- gem 'rails', '~> 6.0.0'
5
+ gem 'rails', '~> 7.0.0'
6
6
 
7
7
  group :test do
8
8
  gem 'mocha', :require => false
data/test/dummy/Gemfile CHANGED
@@ -6,7 +6,7 @@ gem 'wagons', :path => File.expand_path(__FILE__).split("test#{File::SEPARATOR}d
6
6
 
7
7
  group :development, :test do
8
8
  gem 'net-smtp'
9
- gem 'sqlite3'
9
+ gem 'sqlite3', '~> 1.4'
10
10
  end
11
11
 
12
12
  group :test do