bullet_train 1.0.41 ā 1.0.46
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/helpers/account/locale_helper.rb +2 -2
- data/app/models/invitation.rb +1 -1
- data/app/models/membership.rb +1 -1
- data/app/models/team.rb +2 -2
- data/app/models/user.rb +1 -1
- data/docs/indirection.md +62 -2
- data/docs/overriding.md +11 -43
- data/lib/bullet_train/resolver.rb +20 -26
- data/lib/bullet_train/version.rb +1 -1
- data/lib/tasks/bullet_train_tasks.rake +6 -6
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e6c930c4e6fad0f50e6869cdfcceec0b40ac27e4eef3dc04facde80918c9276
|
4
|
+
data.tar.gz: bf9576a58a7c27ac23b46fbacbf93b16a4ac03bae5abc573ffc468e6dce11dc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b6f9ce718307c62a69e49faf9948ba43b1fad9269c49b8562683c9deff3f7c00595d5d0216e2d01bf8b0a25a619164d8e48ca37570b0cbace136ec23fa9b7e3
|
7
|
+
data.tar.gz: 534d607fb41150372dcaea0af84b8aa8fa5897c1af3bf6bab4019cfbb06bf565819a543896dd131b081c39c7081b89144159f42e0118278a304ffd21bd745760
|
@@ -46,7 +46,7 @@ module Account::LocaleHelper
|
|
46
46
|
begin
|
47
47
|
super(key + "š£", options.except(:default))
|
48
48
|
rescue I18n::MissingTranslationData => exception
|
49
|
-
full_key = exception.message.rpartition(" ").last.
|
49
|
+
full_key = exception.message.rpartition(" ").last.delete("š£")
|
50
50
|
end
|
51
51
|
end
|
52
52
|
end
|
@@ -75,7 +75,7 @@ module Account::LocaleHelper
|
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
78
|
-
|
78
|
+
result
|
79
79
|
end
|
80
80
|
|
81
81
|
# like 't', but if the key isn't found, it returns nil.
|
data/app/models/invitation.rb
CHANGED
data/app/models/membership.rb
CHANGED
data/app/models/team.rb
CHANGED
data/app/models/user.rb
CHANGED
data/docs/indirection.md
CHANGED
@@ -1,3 +1,63 @@
|
|
1
|
-
#
|
1
|
+
# Dealing with Indirection
|
2
2
|
|
3
|
-
|
3
|
+
## The Problem with Indirection
|
4
|
+
|
5
|
+
In software development, indirection is everywhere and takes many forms.
|
6
|
+
|
7
|
+
For example, in vanilla Rails development, you introduce a type of indirection when you extract a button label out of a view file and use the `t` helper to render the string from a translation YAML file. In the future, when another developer goes to update the button label, they will first open the view, they'll see `t(".submit")` and then have to reason a little bit about which translation file they need to open up in order to update that label.
|
8
|
+
|
9
|
+
Our goal in Bullet Train is to improve developer experience, not reduce it, so it was important that along with any instances of indirection we were introducing, we also included new tooling to ensure it was never a burden to developers. Thankfully, in practice we found that some of this new tooling improves even layers of indirection that have always been with us in Rails development.
|
10
|
+
|
11
|
+
## Figuring Out Class Locations
|
12
|
+
|
13
|
+
Most of Bullet Train's functionality is distributed via Ruby gems, not the starter template. As a result, the power of fuzzy searching in your IDE is more limited. For example, `app/controllers/account/users_controller.rb` includes its base functionality from a concern called `Account::Users::ControllerBase`. If you try to fuzzy search for it, you'll quickly find the module isn't included in your application repository. However, you can quickly figure out which Ruby gem is providing that concern and inspect it's source by running:
|
14
|
+
|
15
|
+
```
|
16
|
+
bin/resolve Account::Users::ControllerBase --open
|
17
|
+
```
|
18
|
+
|
19
|
+
If you need to modify behavior in these framework-provided classes or modules, see the documentation for [Overriding Framework Defaults](/docs/overriding.md).
|
20
|
+
|
21
|
+
## Solving Indirection in Views
|
22
|
+
|
23
|
+
### Resolving Partial Paths with `bin/resolve`
|
24
|
+
|
25
|
+
Even in vanilla Rails development, when you're looking at a view file, the path you see passed to a `render` call isn't the actual file name of the partial that will be rendered. This is even more true in Bullet Train where certain partial paths are [magically served from theme gems](/docs/themes.md).
|
26
|
+
|
27
|
+
`bin/resolve` makes it easy to figure out where where a partial is being served from:
|
28
|
+
|
29
|
+
```
|
30
|
+
$ bin/resolve shared/box
|
31
|
+
```
|
32
|
+
|
33
|
+
### Exposing Rendered Views with Xray
|
34
|
+
|
35
|
+
> TODO Is this still true in Rails 7? Does it not do something like this by default now?
|
36
|
+
|
37
|
+
If you're looking at a rendered view in the browser, it can be hard to know which file to open in order to make a change. To help, Bullet Train includes [Xray](https://github.com/brentd/xray-rails) by default, so you can right click on any element you see, select "Inspect Element", and you'll see comments in the HTML source telling you which file is powering a particular portion of the view, like this:
|
38
|
+
|
39
|
+
```
|
40
|
+
<!--XRAY START 90 /Users/andrewculver/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/bullet_train-themes-light-1.0.10/app/views/themes/light/workflow/_box.html.erb-->
|
41
|
+
```
|
42
|
+
|
43
|
+
Note that in the example above, the view in question isn't actually coming from the application repository. Instead, it's being included from the `bullet_train-themes-light` package. For instructions on how to customize it, see [Overriding the Framework](/docs/override).
|
44
|
+
|
45
|
+
### Drilling Down on Translation Keys
|
46
|
+
|
47
|
+
Even in vanilla Rails applications, extracting strings from view files into I18N translation YAML files introduces a layer of indirection. Bullet Train tries to improve the resulting DX with a couple tools that make it easier to figure out where a translation you see in your browser is coming from.
|
48
|
+
|
49
|
+
#### Show Translation Keys in the Browser with `?show_locales=true`
|
50
|
+
|
51
|
+
You can see the full translation key of any string on the page by adding `?show_locales=true` to the URL.
|
52
|
+
|
53
|
+
#### Log Translation Keys to the Console with `?log_locales=true`
|
54
|
+
|
55
|
+
You can also log all the translation key for anything being rendered to the console by adding `?log_locales=true` to the request URL. This can make it easier to copy and paste translation keys for strings that are rendered in non-selectable UI elements.
|
56
|
+
|
57
|
+
#### Resolving Translation Keys with `bin/resolve`
|
58
|
+
|
59
|
+
Once you have the full I18N translation key, you can use `bin/resolve` to figure out which package and file it's coming from. At that point, if you need to customize it, you can also use the `--eject` option to copy the the framework for customization in your local application:
|
60
|
+
|
61
|
+
```
|
62
|
+
$ bin/resolve en.account.onboarding.user_details.edit.header --eject --open
|
63
|
+
```
|
data/docs/overriding.md
CHANGED
@@ -1,53 +1,21 @@
|
|
1
|
-
#
|
1
|
+
# Overriding Framework Defaults
|
2
2
|
|
3
|
-
|
3
|
+
Most of Bullet Train's functionality is distributed via Ruby gems, not the starter template. We provide the `bin/resolve` tool to help developers figure out which Ruby gem packages are providing which classes, modules, views, and translations, and its usage is covered in the [Dealing With Indirection](/docs/indirection.md) section of the documentation.
|
4
4
|
|
5
|
-
In
|
5
|
+
However, sometimes you will need to do more than just understand where something is coming from and how it works in the framework. In some situations, you'll specifically want to change or override the default framework behavior. The primary workflow for doing this is much the same as the `bin/resolve` workflow for dealing with indirection in the first place, however, instead of just using `--open` to inspect the source of the framework-provided file, you can add `--eject` to have that file copied into the local repository. From there, it will act as a replacement for the framework-provided file, and you can modify the behavior as needed.
|
6
6
|
|
7
|
-
|
7
|
+
## The Important Role of Active Support Concerns in Bullet Train Customization
|
8
8
|
|
9
|
-
|
9
|
+
When it comes to object-oriented classes, wholesale copying framework files into your local repository just to be able to modify their behavior or extend them would quickly be untenable, as your app would no longer see upstream updates that would otherwise be incorporated into your application via `bundle update`.
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
### Resolving Partial Paths with `bin/resolve`
|
14
|
-
|
15
|
-
Even in vanilla Rails development, when you're looking at a view file, the path you see passed to a `render` call isn't the actual file name of the partial that will be rendered. This is even more true in Bullet Train where certain partial paths are [magically served from theme gems](/docs/themes.md).
|
16
|
-
|
17
|
-
`bin/resolve` makes it easy to figure out where where a partial is being served from:
|
11
|
+
For this reason, common points of extension like framework-provided models and controllers actually exist as a kind of "stub" in the local repository, but include their base functionality from framework-provided concerns, like so:
|
18
12
|
|
19
13
|
```
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
### Exposing Rendered Views with Xray
|
14
|
+
class User < ApplicationRecord
|
15
|
+
include Users::Base
|
24
16
|
|
25
|
-
|
26
|
-
|
27
|
-
If you're looking at a rendered view in the browser, it can be hard to know which file to open in order to make a change. To help, Bullet Train includes [Xray](https://github.com/brentd/xray-rails) by default, so you can right click on any element you see, select "Inspect Element", and you'll see comments in the HTML source telling you which file is powering a particular portion of the view, like this:
|
28
|
-
|
29
|
-
```
|
30
|
-
<!--XRAY START 90 /Users/andrewculver/.rbenv/versions/3.1.1/lib/ruby/gems/3.1.0/gems/bullet_train-themes-light-1.0.10/app/views/themes/light/workflow/_box.html.erb-->
|
17
|
+
# ...
|
18
|
+
end
|
31
19
|
```
|
32
20
|
|
33
|
-
|
34
|
-
|
35
|
-
### Drilling Down on Translation Keys
|
36
|
-
|
37
|
-
Even in vanilla Rails applications, extracting strings from view files into I18N translation YAML files introduces a layer of indirection. Bullet Train tries to improve the resulting DX with a couple tools that make it easier to figure out where a translation you see in your browser is coming from.
|
38
|
-
|
39
|
-
#### Show Translation Keys in the Browser with `?show_locales=true`
|
40
|
-
|
41
|
-
You can see the full translation key of any string on the page by adding `?show_locales=true` to the URL.
|
42
|
-
|
43
|
-
#### Log Translation Keys to the Console with `?log_locales=true`
|
44
|
-
|
45
|
-
You can also log all the translation key for anything being rendered to the console by adding `?log_locales=true` to the request URL. This can make it easier to copy and paste translation keys for strings that are rendered in non-selectable UI elements.
|
46
|
-
|
47
|
-
#### Resolving Translation Keys with `bin/resolve`
|
48
|
-
|
49
|
-
Once you have the full I18N translation key, you can use `bin/resolve` to figure out which package and file it's coming from. At that point, if you need to customize it, you can also use the `--eject` option to copy the the framework for customization in your local application:
|
50
|
-
|
51
|
-
```
|
52
|
-
$ bin/resolve en.account.onboarding.user_details.edit.header --eject --open
|
53
|
-
```
|
21
|
+
In this case, for most customizations or extensions you would want to make, you don't need to eject `Users::Core` into your local repository. Instead, you can simply re-define methods from that concern in your local `User` model after the inclusion of the concern.
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "io/wait"
|
2
2
|
|
3
3
|
module BulletTrain
|
4
4
|
class Resolver
|
@@ -13,28 +13,26 @@ module BulletTrain
|
|
13
13
|
source_file = calculate_source_file_details
|
14
14
|
|
15
15
|
if source_file[:absolute_path]
|
16
|
+
puts ""
|
16
17
|
if source_file[:package_name].present?
|
17
|
-
puts ""
|
18
18
|
puts "Absolute path:".green
|
19
19
|
puts " #{source_file[:absolute_path]}".green
|
20
20
|
puts ""
|
21
21
|
puts "Package name:".green
|
22
22
|
puts " #{source_file[:package_name]}".green
|
23
|
-
puts ""
|
24
23
|
else
|
25
|
-
puts ""
|
26
24
|
puts "Project path:".green
|
27
25
|
puts " #{source_file[:project_path]}".green
|
28
26
|
puts ""
|
29
27
|
puts "Note: If this file was previously ejected from a package, we can no longer see which package it came from. However, it should say at the top of the file where it was ejected from.".yellow
|
30
|
-
puts ""
|
31
28
|
end
|
29
|
+
puts ""
|
32
30
|
|
33
31
|
if interactive && !eject
|
34
32
|
puts "\nWould you like to eject the file into the local project? (y/n)\n"
|
35
33
|
input = $stdin.gets
|
36
34
|
$stdin.getc while $stdin.ready?
|
37
|
-
if input.first.downcase ==
|
35
|
+
if input.first.downcase == "y"
|
38
36
|
eject = true
|
39
37
|
end
|
40
38
|
end
|
@@ -46,7 +44,7 @@ module BulletTrain
|
|
46
44
|
else
|
47
45
|
`mkdir -p #{source_file[:project_path].split("/")[0...-1].join("/")}`
|
48
46
|
puts "Ejecting `#{source_file[:absolute_path]}` to `#{source_file[:project_path]}`".green
|
49
|
-
File.open(
|
47
|
+
File.open((source_file[:project_path]).to_s, "w+") do |file|
|
50
48
|
case source_file[:project_path].split(".").last
|
51
49
|
when "rb", "yml"
|
52
50
|
file.puts "# Ejected from `#{source_file[:package_name]}`.\n\n"
|
@@ -69,13 +67,13 @@ module BulletTrain
|
|
69
67
|
puts "\nWould you like to open `#{source_file[:absolute_path]}`? (y/n)\n"
|
70
68
|
input = $stdin.gets
|
71
69
|
$stdin.getc while $stdin.ready?
|
72
|
-
if input.first.downcase ==
|
70
|
+
if input.first.downcase == "y"
|
73
71
|
open = true
|
74
72
|
end
|
75
73
|
end
|
76
74
|
|
77
75
|
if open
|
78
|
-
path = source_file[:package_name] ? source_file[:absolute_path] :
|
76
|
+
path = source_file[:package_name] ? source_file[:absolute_path] : (source_file[:project_path]).to_s
|
79
77
|
puts "Opening `#{path}`.\n".green
|
80
78
|
exec "open #{path}"
|
81
79
|
end
|
@@ -121,25 +119,21 @@ module BulletTrain
|
|
121
119
|
end
|
122
120
|
|
123
121
|
def class_path
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
return false
|
129
|
-
end
|
122
|
+
@needle.constantize
|
123
|
+
Object.const_source_location(@needle).first
|
124
|
+
rescue NameError => _
|
125
|
+
false
|
130
126
|
end
|
131
127
|
|
132
128
|
def partial_path
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
raise "It looks like Xray-rails isn't properly enabled?"
|
139
|
-
end
|
140
|
-
rescue ActionView::Template::Error => _
|
141
|
-
return nil
|
129
|
+
xray_path = ApplicationController.render(template: "bullet_train/partial_resolver", layout: nil, assigns: {needle: @needle}).lines[1].chomp
|
130
|
+
if xray_path =~ /<!--XRAY START \d+ (.*)-->/
|
131
|
+
$1
|
132
|
+
else
|
133
|
+
raise "It looks like Xray-rails isn't properly enabled?"
|
142
134
|
end
|
135
|
+
rescue ActionView::Template::Error => _
|
136
|
+
nil
|
143
137
|
end
|
144
138
|
|
145
139
|
def file_path
|
@@ -149,7 +143,7 @@ module BulletTrain
|
|
149
143
|
|
150
144
|
def locale_path
|
151
145
|
# This is a complete list of translation files provided by this app or any linked Bullet Train packages.
|
152
|
-
(["#{Rails.root
|
146
|
+
(["#{Rails.root}/config/locales"] + `find ./tmp/gems/*`.lines.map(&:strip).map { |link| File.readlink(link) + "/config/locales" }).each do |locale_source|
|
153
147
|
if File.exist?(locale_source)
|
154
148
|
`find -L #{locale_source} | grep ".yml"`.lines.map(&:strip).each do |file_path|
|
155
149
|
yaml = YAML.load_file(file_path, aliases: true)
|
@@ -161,7 +155,7 @@ module BulletTrain
|
|
161
155
|
end
|
162
156
|
end
|
163
157
|
|
164
|
-
|
158
|
+
nil
|
165
159
|
end
|
166
160
|
end
|
167
161
|
end
|
data/lib/bullet_train/version.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
require
|
1
|
+
require "io/wait"
|
2
2
|
|
3
3
|
namespace :bt do
|
4
4
|
desc "Symlink registered gems in `./tmp/gems` so their views, etc. can be inspected by Tailwind CSS."
|
5
|
-
task :
|
6
|
-
if Dir.
|
5
|
+
task link: :environment do
|
6
|
+
if Dir.exist?("tmp/gems")
|
7
7
|
puts "Removing previously linked gems."
|
8
8
|
`rm -f tmp/gems/*`
|
9
9
|
else
|
10
|
-
if File.
|
10
|
+
if File.exist?("tmp/gems")
|
11
11
|
raise "A file named `tmp/gems` already exists? It has to be removed before we can create the required directory."
|
12
12
|
end
|
13
13
|
|
@@ -43,7 +43,7 @@ namespace :bullet_train do
|
|
43
43
|
$stdin.getc while $stdin.ready?
|
44
44
|
|
45
45
|
# Extract absolute paths from XRAY comments.
|
46
|
-
if input
|
46
|
+
if input =~ /<!--XRAY START \d+ (.*)-->/
|
47
47
|
input = $1
|
48
48
|
end
|
49
49
|
|
@@ -53,7 +53,7 @@ namespace :bullet_train do
|
|
53
53
|
if ARGV.first.present?
|
54
54
|
BulletTrain::Resolver.new(ARGV.first).run(eject: ARGV.include?("--eject"), open: ARGV.include?("--open"), force: ARGV.include?("--force"), interactive: ARGV.include?("--interactive"))
|
55
55
|
else
|
56
|
-
|
56
|
+
warn "\nš
Usage: `bin/resolve [path, partial, or URL] (--eject) (--open)`\n".blue
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bullet_train
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.46
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Culver
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: standard
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rails
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|