rails-worktrees 0.5.0 → 0.5.1

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: 9f11c54fe45c6061774b7181c80c7a25ba1c824d04fe06668ca0d6fe0bc3c453
4
- data.tar.gz: 9470d8a967f77f0188679e8f9b50fd5a78c4aebe6f10e268cba00ffaff1ebea0
3
+ metadata.gz: 698795e04a67284039d3beba2286f3a9aa156a5856832a345f22ffa57b6177e3
4
+ data.tar.gz: 0a57ef25c66c3226798498476abf8caf033c6a2989ae170b30a161fde66fddcf
5
5
  SHA512:
6
- metadata.gz: c3775b72de293d0cf888f9b94cbbeae5b6031f001c641a1365f8f2662caa38de8b04bd4235a4e5c3f7b81279f6a23ce4637f4b2cfa6d6e1ba9d0fd0619daede2
7
- data.tar.gz: 0c07249ae8bad61d6ae0cdad68f58752579145175e0d43005772e0d91f2f04b8d672f99a1952ce168e881d04e0b88ab4bbb8603183d4a9a2ace12f5c1767584e
6
+ metadata.gz: 06c8ae396186a19c08e45445e031a28198d48f7ea5125c02e63b2df39977f5399f75421e7f1897071d14b00d042051616ed4e447b83b570852d54756d8689377
7
+ data.tar.gz: 800a19ef60af420e03280b8a30c02c9012c4ded0d3eaecc421ed5e42e072b8024a0cbc93e7ba7aaf7d806dc972deacacbb0c5edfe45da40b2ab05659b1ccc5c5
@@ -1 +1 @@
1
- {".":"0.5.0"}
1
+ {".":"0.5.1"}
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.1](https://github.com/asjer/rails-worktrees/compare/v0.5.0...v0.5.1) (2026-04-02)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **initializer:** simplify generated config wiring ([bd7fd50](https://github.com/asjer/rails-worktrees/commit/bd7fd506f2c0106a0bd188e36b31329a9de2acbf))
9
+
3
10
  ## [0.5.0](https://github.com/asjer/rails-worktrees/compare/v0.4.0...v0.5.0) (2026-04-02)
4
11
 
5
12
 
data/README.md CHANGED
@@ -19,7 +19,7 @@ bin/rails generate worktrees:install --browser
19
19
  bin/rails generate worktrees:install --yolo
20
20
  ```
21
21
 
22
- The generated initializer checks that `rails-worktrees` is actually loaded before it calls `Rails::Worktrees.configure`, so the app can still boot in environments like `test` when the gem is only bundled for `:development`.
22
+ The generated initializer writes app config under `Rails.application.config.x.rails_worktrees`, so the file stays safe to load even in environments like `test` where the gem is only bundled for `:development`. When `rails-worktrees` is loaded, the gem applies those settings for both the CLI and in-process Rails usage.
23
23
 
24
24
  The installer adds:
25
25
 
@@ -148,7 +148,7 @@ Worktree names must not contain `/` or whitespace, must not be `.` or `..`, and
148
148
 
149
149
  The installer generates `config/initializers/rails_worktrees.rb` where you can override:
150
150
 
151
- The initializer becomes a no-op whenever `rails-worktrees` is not loaded in the current bundle groups.
151
+ The initializer stays app-owned and gem-agnostic; `rails-worktrees` reads those settings whenever the gem is present in the current bundle groups.
152
152
 
153
153
  | Option | Default | Description |
154
154
  |--------|---------|-------------|
@@ -1,23 +1,19 @@
1
- if Gem.loaded_specs.key?('rails-worktrees') &&
2
- defined?(Rails::Worktrees) &&
3
- Rails::Worktrees.respond_to?(:configure)
4
- Rails::Worktrees.configure do |config|
1
+ Rails.application.config.x.rails_worktrees.tap do |config|
5
2
  <% if options['conductor'] -%>
6
- config.workspace_root = <%= conductor_workspace_root %>
3
+ config.workspace_root = <%= conductor_workspace_root %>
7
4
  <% else -%>
8
- # By default, worktrees go in a sibling "<project>.worktrees" directory.
9
- # Uncomment to override with a custom parent directory that uses <root>/<project>/<name>.
10
- # config.workspace_root = File.expand_path('~/worktrees')
5
+ # By default, worktrees go in a sibling "<project>.worktrees" directory.
6
+ # Uncomment to override with a custom parent directory that uses <root>/<project>/<name>.
7
+ # config.workspace_root = File.expand_path('~/worktrees')
11
8
  <% end -%>
12
- # config.bootstrap_env = false
13
- # config.dev_port_range = 3000..3999
14
- # config.worktree_database_suffix_max_length = 18
15
- # config.branch_prefix = '🚂'
16
- # config.name_sources_path = Rails.root.join('config/worktree_names').to_s
17
- # config.used_names_file = File.join(
18
- # ENV.fetch('XDG_STATE_HOME', File.expand_path('~/.local/state')),
19
- # 'rails-worktrees',
20
- # 'used-names.tsv'
21
- # )
22
- end
23
- end
9
+ # config.bootstrap_env = false
10
+ # config.dev_port_range = 3000..3999
11
+ # config.worktree_database_suffix_max_length = 18
12
+ # config.branch_prefix = '🚂'
13
+ # config.name_sources_path = Rails.root.join('config/worktree_names').to_s
14
+ # config.used_names_file = File.join(
15
+ # ENV.fetch('XDG_STATE_HOME', File.expand_path('~/.local/state')),
16
+ # 'rails-worktrees',
17
+ # 'used-names.tsv'
18
+ # )
19
+ end
@@ -0,0 +1,36 @@
1
+ module Rails
2
+ module Worktrees
3
+ # Copies explicit app configuration values onto the runtime configuration object.
4
+ module ApplicationConfiguration
5
+ module_function
6
+
7
+ def apply(source, configuration:)
8
+ return configuration unless source
9
+
10
+ Configuration::CONFIGURABLE_ATTRIBUTES.each do |attribute|
11
+ next unless assigned?(source, attribute)
12
+
13
+ configuration.public_send("#{attribute}=", value_for(source, attribute))
14
+ end
15
+
16
+ configuration
17
+ end
18
+
19
+ def assigned?(source, attribute)
20
+ key = attribute.to_sym
21
+ hash = source.is_a?(Hash) ? source : source.to_h if source.respond_to?(:to_h)
22
+ return hash.key?(key) || hash.key?(attribute.to_s) if hash
23
+
24
+ source.respond_to?(:key?) && (source.key?(key) || source.key?(attribute.to_s))
25
+ end
26
+
27
+ def value_for(source, attribute)
28
+ key = attribute.to_sym
29
+ hash = source.is_a?(Hash) ? source : source.to_h if source.respond_to?(:to_h)
30
+ return hash.fetch(key) { hash[attribute.to_s] } if hash
31
+
32
+ source.public_send(attribute)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,9 @@ module Rails
2
2
  module Worktrees
3
3
  # Shell entrypoint for the wt executable.
4
4
  class CLI
5
+ LOADER_OPTIONAL_COMMANDS = %w[doctor update -h --help -v --version].freeze
6
+ LOADER_IGNORED_FLAGS = %w[--dry-run --force].freeze
7
+
5
8
  def initialize(
6
9
  argv: ARGV,
7
10
  io: { stdin: $stdin, stdout: $stdout, stderr: $stderr },
@@ -15,13 +18,36 @@ module Rails
15
18
  end
16
19
 
17
20
  def start
18
- Command.new(
19
- argv: @argv,
20
- io: @io,
21
- env: @env,
22
- cwd: @cwd,
23
- configuration: ::Rails::Worktrees.configuration
24
- ).run
21
+ configuration = ::Rails::Worktrees.configuration
22
+ load_project_configuration(configuration) if should_load_project_configuration?
23
+ command_for(configuration).run
24
+ rescue ::Rails::Worktrees::Error => e
25
+ @io.fetch(:stderr).puts("Error: #{e.message}")
26
+ 1
27
+ end
28
+
29
+ private
30
+
31
+ def load_project_configuration(configuration)
32
+ ::Rails::Worktrees::ProjectConfigurationLoader.new(root: @cwd, configuration: configuration).call
33
+ rescue StandardError, ScriptError => e
34
+ raise ::Rails::Worktrees::Error, "Failed to load worktrees configuration: #{e.class}: #{e.message}"
35
+ end
36
+
37
+ def should_load_project_configuration?
38
+ argv_without_flags.empty? || !loader_optional_command?(argv_without_flags.first)
39
+ end
40
+
41
+ def argv_without_flags
42
+ @argv.reject { |arg| LOADER_IGNORED_FLAGS.include?(arg) }
43
+ end
44
+
45
+ def loader_optional_command?(command)
46
+ LOADER_OPTIONAL_COMMANDS.include?(command)
47
+ end
48
+
49
+ def command_for(configuration)
50
+ Command.new(argv: @argv, io: @io, env: @env, cwd: @cwd, configuration: configuration)
25
51
  end
26
52
  end
27
53
  end
@@ -2,6 +2,16 @@ module Rails
2
2
  module Worktrees
3
3
  # Stores application-level settings for the wt command.
4
4
  class Configuration
5
+ CONFIGURABLE_ATTRIBUTES = %i[
6
+ bootstrap_env
7
+ workspace_root
8
+ dev_port_range
9
+ branch_prefix
10
+ name_sources_path
11
+ used_names_file
12
+ worktree_database_suffix_max_length
13
+ ].freeze
14
+
5
15
  DEFAULT_BOOTSTRAP_ENV = true
6
16
  DEFAULT_BRANCH_PREFIX = '🚂'.freeze
7
17
  DEFAULT_DEV_PORT_RANGE = (3000..3999)
@@ -2,7 +2,7 @@ require 'erb'
2
2
 
3
3
  module Rails
4
4
  module Worktrees
5
- # Safely updates the generated initializer to use the current gem-loading guard.
5
+ # Safely updates the generated initializer to use the current managed app-config format.
6
6
  # rubocop:disable Metrics/ClassLength
7
7
  class InitializerUpdater
8
8
  Result = Struct.new(:content, :changed, :status, :messages) do
@@ -12,18 +12,13 @@ module Rails
12
12
  end
13
13
 
14
14
  TEMPLATE_PATH = File.expand_path('../../generators/rails/worktrees/templates/rails_worktrees.rb.tt', __dir__)
15
- CURRENT_GUARD_LINES = [
16
- "if Gem.loaded_specs.key?('rails-worktrees') &&",
17
- ' defined?(Rails::Worktrees) &&',
18
- ' Rails::Worktrees.respond_to?(:configure)'
19
- ].freeze
15
+ CURRENT_WRAPPER_CALL = 'Rails.application.config.x.rails_worktrees.tap do |config|'.freeze
16
+ CONFIGURE_CALL = 'Rails::Worktrees.configure do |config|'.freeze
20
17
  KNOWN_GUARD_FRAGMENTS = [
21
18
  "Gem.loaded_specs.key?('rails-worktrees')",
22
19
  'defined?(Rails::Worktrees)',
23
20
  'Rails::Worktrees.respond_to?(:configure)'
24
21
  ].freeze
25
- CONFIGURE_CALL = 'Rails::Worktrees.configure do |config|'.freeze
26
- LEGACY_GUARD = /\Aif defined\?\(Rails::Worktrees\)\n(?<body>.*)\nend\z/m
27
22
 
28
23
  def self.default_content = new(content: '').send(:render_default_template)
29
24
 
@@ -46,7 +41,7 @@ module Rails
46
41
  @content,
47
42
  false,
48
43
  :identical,
49
- ['config/initializers/rails_worktrees.rb already uses the current safety guard.']
44
+ ['config/initializers/rails_worktrees.rb already uses the current managed initializer format.']
50
45
  )
51
46
  end
52
47
 
@@ -55,7 +50,7 @@ module Rails
55
50
  content,
56
51
  content != @content,
57
52
  :updated,
58
- ['Updated config/initializers/rails_worktrees.rb to use the current safety guard.']
53
+ ['Updated config/initializers/rails_worktrees.rb to use the current managed initializer format.']
59
54
  )
60
55
  end
61
56
 
@@ -70,19 +65,20 @@ module Rails
70
65
 
71
66
  def blank_content? = @content.to_s.strip.empty?
72
67
 
73
- def current_guard_present?
74
- !extract_known_guard_body(@content.to_s.strip.lines, required_guard_lines: CURRENT_GUARD_LINES).nil?
68
+ def current_wrapper_present?
69
+ !extract_current_wrapper_body(@content.to_s.strip.lines).nil?
75
70
  end
76
71
 
77
- def wrapped_body = extract_existing_body&.then { |body| normalize_body(body) }
72
+ def normalized_body = extract_existing_body&.then { |body| normalize_body(body) }
78
73
 
79
74
  def extract_existing_body
80
75
  stripped = @content.to_s.strip
81
76
  return if stripped.empty?
82
77
 
83
- return Regexp.last_match[:body] if stripped.match(LEGACY_GUARD)
78
+ body = extract_current_wrapper_body(stripped.lines)
79
+ return body if body
84
80
 
85
- body = extract_known_guard_body(stripped.lines)
81
+ body = extract_guarded_configure_body(stripped.lines)
86
82
  return body if body
87
83
 
88
84
  body = extract_plain_configure_body(stripped.lines)
@@ -91,25 +87,25 @@ module Rails
91
87
  nil
92
88
  end
93
89
 
94
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
95
- def extract_known_guard_body(lines, required_guard_lines: nil)
96
- return if lines.empty? || lines.last.strip != 'end'
90
+ def extract_current_wrapper_body(lines)
91
+ return unless lines.first&.strip == CURRENT_WRAPPER_CALL && lines.last&.strip == 'end'
97
92
 
98
- configure_index = lines.index { |line| line.strip == CONFIGURE_CALL }
99
- return unless configure_index
93
+ lines[1...-1].join.rstrip
94
+ end
95
+
96
+ def extract_guarded_configure_body(lines)
97
+ return unless guarded_configure_block?(lines)
100
98
 
101
- guard_lines = lines[0...configure_index].reject { |line| line.strip.empty? }.map(&:rstrip)
102
- return unless guard_lines.all? { |line| known_guard_line?(line) }
103
- return if required_guard_lines && guard_lines != required_guard_lines
99
+ configure_index = lines.index { |line| line.strip == CONFIGURE_CALL }
100
+ return unless guarded_configure_lines(lines, configure_index).all? { |line| known_guard_line?(line) }
104
101
 
105
- lines[configure_index...-1].join.rstrip
102
+ lines[(configure_index + 1)...-2].join.rstrip
106
103
  end
107
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
108
104
 
109
105
  def extract_plain_configure_body(lines)
110
106
  return unless lines.first&.strip == CONFIGURE_CALL && lines.last&.strip == 'end'
111
107
 
112
- lines.join.rstrip
108
+ lines[1...-1].join.rstrip
113
109
  end
114
110
 
115
111
  def known_guard_line?(line)
@@ -124,13 +120,17 @@ module Rails
124
120
  body_lines = body.rstrip.lines
125
121
  return '' if body_lines.empty?
126
122
 
127
- return body.rstrip if body_lines.first.start_with?(' ')
123
+ minimum_indent = body_indent(body_lines)
128
124
 
129
- body_lines.map { |line| line.strip.empty? ? line : " #{line}" }.join.rstrip
125
+ body_lines.map do |line|
126
+ next line if line.strip.empty?
127
+
128
+ normalize_body_line(line, minimum_indent)
129
+ end.join.rstrip
130
130
  end
131
131
 
132
132
  def rebuild_content(body)
133
- content = [CURRENT_GUARD_LINES.join("\n"), body, 'end'].join("\n")
133
+ content = [CURRENT_WRAPPER_CALL, body, 'end'].join("\n")
134
134
  @content.end_with?("\n") || @content.empty? ? "#{content}\n" : content
135
135
  end
136
136
 
@@ -142,6 +142,29 @@ module Rails
142
142
  Struct.new(:options, :conductor_workspace_root).new({ 'conductor' => false },
143
143
  "File.expand_path('~/Sites/conductor/workspaces')")
144
144
  end
145
+
146
+ def guarded_configure_block?(lines)
147
+ lines.last(2).map(&:strip) == %w[end end] && lines.any? { |line| line.strip == CONFIGURE_CALL }
148
+ end
149
+
150
+ def guarded_configure_lines(lines, configure_index)
151
+ lines[0...configure_index].reject { |line| line.strip.empty? }.map(&:rstrip)
152
+ end
153
+
154
+ def body_indent(body_lines)
155
+ body_lines.reject { |line| line.strip.empty? }
156
+ .map { |line| line[/\A\s*/].length }
157
+ .min || 0
158
+ end
159
+
160
+ def normalize_body_line(line, minimum_indent)
161
+ trimmed = line.sub(/\A\s{0,#{minimum_indent}}/, '')
162
+ " #{trimmed}"
163
+ end
164
+
165
+ def current_guard_present? = current_wrapper_present?
166
+
167
+ def wrapped_body = normalized_body
145
168
  end
146
169
  # rubocop:enable Metrics/ClassLength
147
170
  end
@@ -0,0 +1,205 @@
1
+ require 'pathname'
2
+
3
+ module Rails
4
+ module Worktrees
5
+ # Loads project-level configuration from the generated initializer without booting the full app.
6
+ class ProjectConfigurationLoader
7
+ CURRENT_WRAPPER_CALL = 'Rails.application.config.x.rails_worktrees.tap do |config|'.freeze
8
+ CONFIGURE_CALL = 'Rails::Worktrees.configure do |config|'.freeze
9
+ INITIALIZER_RELATIVE_PATH = 'config/initializers/rails_worktrees.rb'.freeze
10
+ KNOWN_GUARD_FRAGMENTS = [
11
+ "Gem.loaded_specs.key?('rails-worktrees')",
12
+ 'defined?(Rails::Worktrees)',
13
+ 'Rails::Worktrees.respond_to?(:configure)'
14
+ ].freeze
15
+ TEMP_RAILS_ROOT_MUTEX = Mutex.new
16
+
17
+ def initialize(root:, configuration: Rails::Worktrees.configuration)
18
+ @root = root
19
+ @configuration = configuration
20
+ end
21
+
22
+ def call
23
+ return configuration unless initializer_path && File.file?(initializer_path)
24
+
25
+ body = extract_configuration_body(File.read(initializer_path))
26
+ return configuration unless body
27
+
28
+ recorder = AssignmentRecorder.new(configuration)
29
+
30
+ with_temporary_rails_root do
31
+ evaluate_configuration_body(body, recorder)
32
+ end
33
+
34
+ Rails::Worktrees.apply_application_configuration(recorder.values, configuration: configuration)
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :configuration, :root
40
+
41
+ def initializer_path
42
+ return @initializer_path if defined?(@initializer_path)
43
+
44
+ @initializer_path = project_root&.join(INITIALIZER_RELATIVE_PATH)&.to_s
45
+ end
46
+
47
+ def project_root
48
+ return @project_root if defined?(@project_root)
49
+
50
+ @project_root = discover_project_root
51
+ end
52
+
53
+ def discover_project_root
54
+ current = Pathname(root).expand_path
55
+
56
+ current.ascend do |path|
57
+ return path if File.file?(path.join(INITIALIZER_RELATIVE_PATH))
58
+ end
59
+
60
+ nil
61
+ end
62
+
63
+ def evaluate_configuration_body(body, recorder)
64
+ # Evaluates a managed initializer body like:
65
+ #
66
+ # proc do |config|
67
+ # config.branch_prefix = '🌿'
68
+ # end
69
+ # rubocop:disable Security/Eval, Style/DocumentDynamicEvalDefinition, Style/EvalWithLocation
70
+ Kernel.eval(
71
+ "proc do |config|\n#{body.rstrip}\nend",
72
+ TOPLEVEL_BINDING,
73
+ initializer_path,
74
+ 1
75
+ ).call(recorder)
76
+ # rubocop:enable Security/Eval, Style/DocumentDynamicEvalDefinition, Style/EvalWithLocation
77
+ end
78
+
79
+ def extract_configuration_body(content)
80
+ stripped = content.to_s.strip
81
+ return if stripped.empty?
82
+
83
+ lines = stripped.lines
84
+
85
+ extract_single_block_body(lines, CURRENT_WRAPPER_CALL) ||
86
+ extract_guarded_configure_body(lines) ||
87
+ extract_single_block_body(lines, CONFIGURE_CALL)
88
+ end
89
+
90
+ def extract_single_block_body(lines, opening_line)
91
+ return unless lines.first&.strip == opening_line && lines.last&.strip == 'end'
92
+
93
+ lines[1...-1].join
94
+ end
95
+
96
+ def extract_guarded_configure_body(lines)
97
+ return unless guarded_configure_block?(lines)
98
+
99
+ configure_index = lines.index { |line| line.strip == CONFIGURE_CALL }
100
+ return unless guarded_configure_lines(lines, configure_index).all? { |line| known_guard_line?(line) }
101
+
102
+ lines[(configure_index + 1)...-2].join
103
+ end
104
+
105
+ def known_guard_line?(line)
106
+ normalized = line.strip.delete_suffix('&&').strip.sub(/\Aif\s+/, '')
107
+ KNOWN_GUARD_FRAGMENTS.include?(normalized)
108
+ end
109
+
110
+ def guarded_configure_block?(lines)
111
+ lines.last(2).map(&:strip) == %w[end end] && lines.any? { |line| line.strip == CONFIGURE_CALL }
112
+ end
113
+
114
+ def guarded_configure_lines(lines, configure_index)
115
+ lines[0...configure_index].reject { |line| line.strip.empty? }.map(&:rstrip)
116
+ end
117
+
118
+ def with_temporary_rails_root
119
+ self.class::TEMP_RAILS_ROOT_MUTEX.synchronize do
120
+ override_state = build_rails_root_override_state
121
+
122
+ apply_temporary_rails_root(override_state, project_root)
123
+ yield
124
+ ensure
125
+ restore_rails_root(override_state)
126
+ end
127
+ end
128
+
129
+ def build_rails_root_override_state
130
+ had_root = Rails.respond_to?(:root)
131
+ { singleton_class: Rails.singleton_class, had_root: had_root,
132
+ previous_root: (Rails.method(:root) if had_root), overridden: false }
133
+ end
134
+
135
+ def apply_temporary_rails_root(override_state, resolved_project_root)
136
+ override_state[:singleton_class].send(:define_method, :root) { resolved_project_root }
137
+ override_state[:overridden] = true
138
+ end
139
+
140
+ def restore_rails_root(override_state)
141
+ return unless override_state
142
+
143
+ override_state[:singleton_class].send(:remove_method, :root) if override_state[:overridden]
144
+ return unless override_state[:had_root]
145
+
146
+ override_state[:singleton_class].send(:define_method, :root, override_state[:previous_root])
147
+ end
148
+
149
+ # Records config.<name> = value assignments without raising on unknown keys.
150
+ class AssignmentRecorder
151
+ attr_reader :values
152
+
153
+ def initialize(configuration = nil)
154
+ @configuration = configuration
155
+ @values = {}
156
+ end
157
+
158
+ def method_missing(method_name, *args)
159
+ name = method_name.to_s
160
+
161
+ if setter_call?(name, args)
162
+ values[name.delete_suffix('=').to_sym] = args.first
163
+ elsif getter_call?(name, args)
164
+ values.fetch(name.to_sym) { configuration_value_for(method_name) }
165
+ else
166
+ super
167
+ end
168
+ end
169
+
170
+ def respond_to_missing?(method_name, include_private = false)
171
+ name = method_name.to_s
172
+
173
+ setter_name?(name) || getter_name?(name) || super
174
+ end
175
+
176
+ private
177
+
178
+ attr_reader :configuration
179
+
180
+ def setter_call?(name, args)
181
+ setter_name?(name) && args.length == 1
182
+ end
183
+
184
+ def getter_call?(name, args)
185
+ getter_name?(name) && args.empty?
186
+ end
187
+
188
+ def setter_name?(name)
189
+ name.end_with?('=')
190
+ end
191
+
192
+ def getter_name?(name)
193
+ !setter_name?(name)
194
+ end
195
+
196
+ def configuration_value_for(method_name)
197
+ fallback_configuration = configuration
198
+ return unless fallback_configuration.respond_to?(method_name)
199
+
200
+ fallback_configuration.public_send(method_name)
201
+ end
202
+ end
203
+ end
204
+ end
205
+ end
@@ -151,7 +151,8 @@ module Rails
151
151
  identifier: :initializer,
152
152
  category: :install,
153
153
  relative_path: 'config/initializers/rails_worktrees.rb',
154
- identical_headline: 'config/initializers/rails_worktrees.rb already uses the current safety guard.',
154
+ identical_headline: 'config/initializers/rails_worktrees.rb already uses the current managed initializer ' \
155
+ 'format.',
155
156
  fixable_headline: 'config/initializers/rails_worktrees.rb can be updated automatically.',
156
157
  warning_headline: 'config/initializers/rails_worktrees.rb needs manual review.'
157
158
  }
@@ -162,7 +163,8 @@ module Rails
162
163
  config,
163
164
  "#{config.fetch(:relative_path)} is missing.",
164
165
  updated_content: InitializerUpdater.default_content,
165
- apply_messages: ['Created config/initializers/rails_worktrees.rb with the current safety guard.']
166
+ apply_messages: ['Created config/initializers/rails_worktrees.rb in the current managed initializer ' \
167
+ 'format.']
166
168
  )
167
169
  end
168
170
 
@@ -5,6 +5,10 @@ module Rails
5
5
  initializer 'rails_worktrees.installation_hint' do
6
6
  Rails::Worktrees.warn_about_missing_installation
7
7
  end
8
+
9
+ initializer 'rails_worktrees.apply_application_config', after: :load_config_initializers do |app|
10
+ Rails::Worktrees.apply_application_configuration(app.config.x.rails_worktrees)
11
+ end
8
12
  end
9
13
  end
10
14
  end
@@ -1,5 +1,5 @@
1
1
  module Rails
2
2
  module Worktrees
3
- VERSION = '0.5.0'.freeze
3
+ VERSION = '0.5.1'.freeze
4
4
  end
5
5
  end
@@ -2,6 +2,7 @@ require 'pathname'
2
2
 
3
3
  require_relative 'worktrees/version'
4
4
  require_relative 'worktrees/configuration'
5
+ require_relative 'worktrees/application_configuration'
5
6
  require_relative 'worktrees/env_bootstrapper'
6
7
  require_relative 'worktrees/command'
7
8
  require_relative 'worktrees/cli'
@@ -11,6 +12,7 @@ require_relative 'worktrees/initializer_updater'
11
12
  require_relative 'worktrees/procfile_updater'
12
13
  require_relative 'worktrees/mise_toml_updater'
13
14
  require_relative 'worktrees/puma_config_updater'
15
+ require_relative 'worktrees/project_configuration_loader'
14
16
  require_relative 'worktrees/project_maintenance'
15
17
 
16
18
  module Rails
@@ -39,6 +41,10 @@ module Rails
39
41
  @configuration = Configuration.new
40
42
  end
41
43
 
44
+ def apply_application_configuration(source, configuration: self.configuration)
45
+ ApplicationConfiguration.apply(source, configuration: configuration)
46
+ end
47
+
42
48
  def installation_complete?(root = resolve_root)
43
49
  return false unless root
44
50
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-worktrees
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.5.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asjer Querido
@@ -55,6 +55,7 @@ files:
55
55
  - lib/generators/rails/worktrees/templates/rails_worktrees.rb.tt
56
56
  - lib/generators/worktrees/install/install_generator.rb
57
57
  - lib/rails/worktrees.rb
58
+ - lib/rails/worktrees/application_configuration.rb
58
59
  - lib/rails/worktrees/browser_command.rb
59
60
  - lib/rails/worktrees/cli.rb
60
61
  - lib/rails/worktrees/command.rb
@@ -70,6 +71,7 @@ files:
70
71
  - lib/rails/worktrees/mise_toml_updater.rb
71
72
  - lib/rails/worktrees/names/cities.txt
72
73
  - lib/rails/worktrees/procfile_updater.rb
74
+ - lib/rails/worktrees/project_configuration_loader.rb
73
75
  - lib/rails/worktrees/project_maintenance.rb
74
76
  - lib/rails/worktrees/puma_config_updater.rb
75
77
  - lib/rails/worktrees/railtie.rb