rails_drivers 0.1.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +71 -5
- data/bin/driver +33 -9
- data/bin/nodriver +11 -0
- data/lib/generators/driver/driver_generator.rb +1 -1
- data/lib/rails_drivers.rb +7 -5
- data/lib/rails_drivers/files.rb +36 -0
- data/lib/rails_drivers/railtie.rb +11 -0
- data/lib/rails_drivers/routes.rb +0 -3
- data/lib/rails_drivers/setup.rb +1 -0
- data/lib/rails_drivers/version.rb +1 -1
- data/lib/tasks/rails_drivers_tasks.rake +7 -30
- metadata +34 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0d06c45078456d085945c12374a78a6e8cd8c5ae83ad7abc7fd55cda175e8c4
|
4
|
+
data.tar.gz: 18d5755774da8c851c0a39a25bcfa061445ac1acc06a98e27b22acb896443ab2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '09235347fa19b0da2ea6f20bebdfc4f2048c51760df3889575d7d6cd376a658ccac01a1053b03feaa7f6f89a329ca60db323aa2eb365b62977e29bd05e20a20c'
|
7
|
+
data.tar.gz: cff5ba12b81d820189e145f8b15535ec8ab42942963cb31eb501c359f4f2561171326d1cf93adab12df6d1a540f2f2465f4cb18c304316049561237409005656
|
data/README.md
CHANGED
@@ -4,20 +4,20 @@
|
|
4
4
|
|
5
5
|
Each driver is like a mini Rails app that has full access to the main app. A driver has its own `app`, `config`, `spec`, and `db` folder.
|
6
6
|
|
7
|
-
Technically speaking, drivers are just a
|
7
|
+
Technically speaking, drivers are just a fancy name for putting code into a different folder. The advantage of doing this is that it provides clear-cut separation of concerns. If we follow a couple of simple rules, we can actually test that separation:
|
8
8
|
|
9
9
|
- Drivers should not touch other drivers
|
10
10
|
- The main app should not touch drivers directly
|
11
11
|
|
12
12
|
The "main app" refers to the files inside your `<project root>/app` directory.
|
13
13
|
|
14
|
-
|
14
|
+
If your test suite is good, you can test that these rules are adhered to by selectively adding and removing drivers before running your tests.
|
15
15
|
|
16
16
|
## Aren't these just engines?
|
17
17
|
|
18
18
|
Very similar, yes. They use the same Rails facilities for adding new `app` paths, etc.
|
19
19
|
|
20
|
-
But Drivers have
|
20
|
+
But Drivers have less friction. They can be freely added and removed from your project without breaking anything. There's no need to mess around with gems, vendoring, or dummy apps.
|
21
21
|
|
22
22
|
## Usage
|
23
23
|
|
@@ -34,6 +34,21 @@ Just run `rails g driver my_new_driver_name`.
|
|
34
34
|
The `driver` utility technically works with other generators and rake tasks, but is only guaranteed to work with migrations.
|
35
35
|
The reason is that some generators assume a particular path, rather than using the Rails path methods.
|
36
36
|
|
37
|
+
### Creating a rake task in a driver
|
38
|
+
|
39
|
+
Every driver includes a `lib/tasks` directory where you can define rake tasks. Rake tasks defined in drivers are automatically loaded and namespaced.
|
40
|
+
For example,
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
# drivers/my_driver/lib/tasks/my_namespace.rake
|
44
|
+
namespace :my_namespace do
|
45
|
+
task :task_name do
|
46
|
+
end
|
47
|
+
end
|
48
|
+
```
|
49
|
+
|
50
|
+
Can be executed using `rake driver:my_driver:my_namespace:task_name`.
|
51
|
+
|
37
52
|
### Testing for coupling
|
38
53
|
|
39
54
|
Since drivers are merged into your main application just like engines, there's nothing stopping them from accessing other drivers, and there's nothing stopping your main application from accessing drivers. In order to ensure those things don't happen, we have a handful of rake tasks:
|
@@ -54,6 +69,11 @@ rake driver:restore
|
|
54
69
|
rake driver:isolate[admin]
|
55
70
|
rspec --pattern '{spec,drivers/*/spec}/**{,/*/**}/*_spec.rb'
|
56
71
|
rake driver:restore
|
72
|
+
|
73
|
+
# Short-hand with 'driver' utility!
|
74
|
+
bundle exec driver admin do rspec --pattern '{spec,drivers/*/spec}/**{,/*/**}/*_spec.rb'
|
75
|
+
# (can run with no drivers as well)
|
76
|
+
bundle exec nodriver do rspec --pattern '{spec,drivers/*/spec}/**{,/*/**}/*_spec.rb'
|
57
77
|
```
|
58
78
|
|
59
79
|
This lets you to ensure that the store and admin function properly without each other. Note we're running all of the main app's specs twice. This is good because we also want to make sure the main app is not reaching into drivers.
|
@@ -72,23 +92,69 @@ And then execute:
|
|
72
92
|
$ bundle install
|
73
93
|
```
|
74
94
|
|
75
|
-
Add this line to your routes.rb
|
95
|
+
Add this line to your routes.rb:
|
76
96
|
|
77
97
|
```ruby
|
78
98
|
require 'rails_drivers/routes'
|
99
|
+
|
100
|
+
# This can go before or after your application's route definitions
|
101
|
+
RailsDrivers::Routes.load_driver_routes
|
79
102
|
```
|
80
103
|
|
81
|
-
|
104
|
+
### RSpec
|
105
|
+
|
106
|
+
If you use RSpec with FactoryBot, add these lines to your `spec/rails_helper.rb` or `spec/spec_helper.rb`:
|
82
107
|
|
83
108
|
```ruby
|
84
109
|
Dir[Rails.root.join("drivers/*/spec/support/*.rb")].each { |f| require f }
|
85
110
|
|
86
111
|
RSpec.configure do |config|
|
112
|
+
FactoryBot.definition_file_paths += Dir['drivers/*/spec/factories']
|
113
|
+
FactoryBot.reload
|
114
|
+
|
87
115
|
Dir[Rails.root.join('drivers/*/spec')].each { |x| config.project_source_dirs << x }
|
88
116
|
Dir[Rails.root.join('drivers/*/lib')].each { |x| config.project_source_dirs << x }
|
89
117
|
Dir[Rails.root.join('drivers/*/app')].each { |x| config.project_source_dirs << x }
|
90
118
|
end
|
91
119
|
```
|
92
120
|
|
121
|
+
### Webpacker
|
122
|
+
|
123
|
+
If you use Webpacker, take a look at this snippet. You'll want to add the code between the comments:
|
124
|
+
|
125
|
+
```javascript
|
126
|
+
// config/webpack/environment.js
|
127
|
+
const { environment } = require('@rails/webpacker')
|
128
|
+
|
129
|
+
//// Begin driver code ////
|
130
|
+
const { config } = require('@rails/webpacker')
|
131
|
+
const { sync } = require('glob')
|
132
|
+
const { basename, dirname, join, relative, resolve } = require('path')
|
133
|
+
const extname = require('path-complete-extname')
|
134
|
+
|
135
|
+
const getExtensionsGlob = () => {
|
136
|
+
const { extensions } = config
|
137
|
+
return extensions.length === 1 ? `**/*${extensions[0]}` : `**/*{${extensions.join(',')}}`
|
138
|
+
}
|
139
|
+
|
140
|
+
const addToEntryObject = (sourcePath) => {
|
141
|
+
const glob = getExtensionsGlob()
|
142
|
+
const rootPath = join(sourcePath, config.source_entry_path)
|
143
|
+
const paths = sync(join(rootPath, glob))
|
144
|
+
paths.forEach((path) => {
|
145
|
+
const namespace = relative(join(rootPath), dirname(path))
|
146
|
+
const name = join(namespace, basename(path, extname(path)))
|
147
|
+
environment.entry.set(name, resolve(path))
|
148
|
+
})
|
149
|
+
}
|
150
|
+
|
151
|
+
sync('drivers/*').forEach((driverPath) => {
|
152
|
+
addToEntryObject(join(driverPath, config.source_path));
|
153
|
+
})
|
154
|
+
//// End driver code ////
|
155
|
+
|
156
|
+
module.exports = environment
|
157
|
+
```
|
158
|
+
|
93
159
|
## License
|
94
160
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/bin/driver
CHANGED
@@ -1,15 +1,39 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
require_relative "#{Dir.pwd}/config/boot"
|
4
|
+
require 'rails_drivers/files'
|
6
5
|
|
7
|
-
|
6
|
+
selected_driver = ARGV.shift
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
if ARGV[0] == 'do'
|
9
|
+
#
|
10
|
+
# Run any command with only one driver present
|
11
|
+
#
|
12
|
+
ARGV.shift
|
13
|
+
at_exit { RailsDrivers::Files.restore }
|
14
|
+
|
15
|
+
if selected_driver == '_clear'
|
16
|
+
RailsDrivers::Files.clear
|
17
|
+
else
|
18
|
+
RailsDrivers::Files.isolate selected_driver
|
19
|
+
end
|
20
|
+
|
21
|
+
Process.wait Process.spawn(*ARGV)
|
22
|
+
exit Process.last_status.exitstatus
|
23
|
+
else
|
24
|
+
#
|
25
|
+
# Run 'rails' command as if the driver was the rails app.
|
26
|
+
#
|
27
|
+
APP_PATH = File.expand_path('config/application')
|
28
|
+
REPLACE_DEFAULT_PATH_WITH_DRIVER = selected_driver
|
14
29
|
|
15
|
-
|
30
|
+
require_relative "#{Dir.pwd}/config/boot"
|
31
|
+
|
32
|
+
possible_drivers = Dir['drivers/*'].map { |d| d.split('/').last }
|
33
|
+
unless possible_drivers.include?(REPLACE_DEFAULT_PATH_WITH_DRIVER)
|
34
|
+
puts "Unknown driver #{REPLACE_DEFAULT_PATH_WITH_DRIVER}. Must be one of [#{possible_drivers.join(', ')}]"
|
35
|
+
exit 1
|
36
|
+
end
|
37
|
+
|
38
|
+
require 'rails/commands'
|
39
|
+
end
|
data/bin/nodriver
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'rails_drivers/files'
|
5
|
+
|
6
|
+
ARGV.shift if ARGV[0] == 'do'
|
7
|
+
|
8
|
+
at_exit { RailsDrivers::Files.restore }
|
9
|
+
RailsDrivers::Files.clear
|
10
|
+
Process.wait Process.spawn(*ARGV)
|
11
|
+
exit Process.last_status.exitstatus
|
@@ -9,7 +9,7 @@ class DriverGenerator < Rails::Generators::NamedBase
|
|
9
9
|
create_file "drivers/#{file_name}/app/views/#{file_name}/.keep", ''
|
10
10
|
create_file "drivers/#{file_name}/spec/.keep", ''
|
11
11
|
create_file "drivers/#{file_name}/db/migrate/.keep", ''
|
12
|
-
create_file "drivers/#{file_name}/lib/.keep", ''
|
12
|
+
create_file "drivers/#{file_name}/lib/tasks/.keep", ''
|
13
13
|
|
14
14
|
template 'routes.rb.erb', "drivers/#{file_name}/config/routes.rb"
|
15
15
|
template 'initializer.rb.erb', "drivers/#{file_name}/config/initializers/#{file_name}_feature.rb"
|
data/lib/rails_drivers.rb
CHANGED
@@ -5,11 +5,13 @@ require 'rails_drivers/setup'
|
|
5
5
|
require 'rails_drivers/railtie'
|
6
6
|
|
7
7
|
module RailsDrivers
|
8
|
-
|
9
|
-
|
10
|
-
|
8
|
+
class << self
|
9
|
+
def loaded
|
10
|
+
@loaded ||= []
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
def freeze!
|
14
|
+
@loaded = @loaded&.freeze
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsDrivers
|
4
|
+
module Files
|
5
|
+
class Error < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def isolate(driver)
|
11
|
+
raise Error, 'No driver specified' if driver.nil? || driver == ''
|
12
|
+
raise Error, "Driver #{driver.inspect} not found" unless File.exist?("drivers/#{driver}")
|
13
|
+
|
14
|
+
FileUtils.mkdir_p 'tmp/drivers'
|
15
|
+
Dir['drivers/*'].each do |driver_path|
|
16
|
+
next if driver_path.include?("/#{driver}")
|
17
|
+
|
18
|
+
FileUtils.mv driver_path, "tmp/#{driver_path}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def clear
|
23
|
+
FileUtils.mkdir_p 'tmp/drivers'
|
24
|
+
Dir['drivers/*'].each do |driver_path|
|
25
|
+
FileUtils.mv driver_path, "tmp/#{driver_path}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def restore
|
30
|
+
Dir['tmp/drivers/*'].each do |tmp_driver_path|
|
31
|
+
driver = tmp_driver_path.split('/').last
|
32
|
+
FileUtils.mv tmp_driver_path, "drivers/#{driver}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -6,6 +6,17 @@ module RailsDrivers
|
|
6
6
|
|
7
7
|
rake_tasks do
|
8
8
|
load File.expand_path("#{__dir__}/../tasks/rails_drivers_tasks.rake")
|
9
|
+
|
10
|
+
# load drivers rake tasks
|
11
|
+
Dir['drivers/*/lib/tasks/**/*.rake'].each do |driver_rake_file|
|
12
|
+
%r{^drivers/(?<driver_name>\w+)/} =~ driver_rake_file
|
13
|
+
|
14
|
+
namespace(:driver) do
|
15
|
+
namespace(driver_name) do
|
16
|
+
load driver_rake_file
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
9
20
|
end
|
10
21
|
|
11
22
|
config.before_configuration { setup_paths }
|
data/lib/rails_drivers/routes.rb
CHANGED
data/lib/rails_drivers/setup.rb
CHANGED
@@ -1,46 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
namespace :driver do
|
4
|
-
DriverError = Class.new(StandardError)
|
5
|
-
|
6
4
|
desc 'Removes every driver but the one specified. Can be undone with driver:restore.'
|
7
5
|
task :isolate, [:driver] do |_t, args|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
raise DriverError, 'Driver not found' unless File.exist?("drivers/#{args.driver}")
|
12
|
-
|
13
|
-
mkdir_p 'tmp/drivers'
|
14
|
-
Dir['drivers/*'].each do |driver_path|
|
15
|
-
next if driver_path.include?("/#{args.driver}")
|
16
|
-
|
17
|
-
mv driver_path, "tmp/#{driver_path}"
|
18
|
-
puts "Moved #{driver_path} to tmp/drivers/"
|
19
|
-
end
|
20
|
-
|
21
|
-
rescue DriverError => e
|
6
|
+
require 'rails_drivers/files'
|
7
|
+
RailsDrivers::Files.isolate(args.driver)
|
8
|
+
rescue RailsDrivers::Files::Error => e
|
22
9
|
puts e.message
|
23
10
|
end
|
24
11
|
|
25
12
|
desc 'Removes all drivers. Can be undone with driver:restore.'
|
26
13
|
task :clear do
|
27
|
-
|
28
|
-
|
29
|
-
mkdir_p 'tmp/drivers'
|
30
|
-
Dir['drivers/*'].each do |driver_path|
|
31
|
-
mv driver_path, "tmp/#{driver_path}"
|
32
|
-
puts "Moved #{driver_path} to tmp/drivers/"
|
33
|
-
end
|
14
|
+
require 'rails_drivers/files'
|
15
|
+
RailsDrivers::Files.clear
|
34
16
|
end
|
35
17
|
|
36
18
|
desc 'Undoes the effects of driver:isolate and driver:clear.'
|
37
19
|
task :restore do
|
38
|
-
|
39
|
-
|
40
|
-
Dir['tmp/drivers/*'].each do |tmp_driver_path|
|
41
|
-
driver = tmp_driver_path.split('/').last
|
42
|
-
mv tmp_driver_path, "drivers/#{driver}"
|
43
|
-
puts "Moved #{tmp_driver_path} to drivers/"
|
44
|
-
end
|
20
|
+
require 'rails_drivers/files'
|
21
|
+
RailsDrivers::Files.restore
|
45
22
|
end
|
46
23
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_drivers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nigel Baillie
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: sqlite3
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,12 +66,27 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: webpacker
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.5'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.5'
|
55
83
|
description: Like Rails Engines, but without the friction. Your Rails app can't access
|
56
84
|
them, and they can't access each other.
|
57
85
|
email:
|
58
86
|
- nbaillie@degica.com
|
59
87
|
executables:
|
60
88
|
- driver
|
89
|
+
- nodriver
|
61
90
|
extensions: []
|
62
91
|
extra_rdoc_files: []
|
63
92
|
files:
|
@@ -65,12 +94,14 @@ files:
|
|
65
94
|
- README.md
|
66
95
|
- Rakefile
|
67
96
|
- bin/driver
|
97
|
+
- bin/nodriver
|
68
98
|
- lib/generators/driver/USAGE
|
69
99
|
- lib/generators/driver/driver_generator.rb
|
70
100
|
- lib/generators/driver/templates/initializer.rb.erb
|
71
101
|
- lib/generators/driver/templates/module.rb.erb
|
72
102
|
- lib/generators/driver/templates/routes.rb.erb
|
73
103
|
- lib/rails_drivers.rb
|
104
|
+
- lib/rails_drivers/files.rb
|
74
105
|
- lib/rails_drivers/railtie.rb
|
75
106
|
- lib/rails_drivers/routes.rb
|
76
107
|
- lib/rails_drivers/setup.rb
|
@@ -95,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
126
|
- !ruby/object:Gem::Version
|
96
127
|
version: '0'
|
97
128
|
requirements: []
|
98
|
-
rubygems_version: 3.0.
|
129
|
+
rubygems_version: 3.0.3
|
99
130
|
signing_key:
|
100
131
|
specification_version: 4
|
101
132
|
summary: De-coupled separation of concerns for Rails
|