create-ruby-app 1.1.0 → 1.3.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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/CLAUDE.md +74 -0
  4. data/CODE_REVIEW.md +1659 -0
  5. data/LICENSE +13 -21
  6. data/README.md +5 -5
  7. data/REFACTORING_PLAN.md +543 -0
  8. data/bin/create-ruby-app +1 -3
  9. data/lib/create_ruby_app/actions/create_directories.rb +10 -2
  10. data/lib/create_ruby_app/actions/generate_files.rb +7 -4
  11. data/lib/create_ruby_app/actions/install_gems.rb +10 -2
  12. data/lib/create_ruby_app/actions/make_script_executable.rb +10 -2
  13. data/lib/create_ruby_app/actions/set_ruby_implementation.rb +52 -0
  14. data/lib/create_ruby_app/app.rb +9 -8
  15. data/lib/create_ruby_app/cli.rb +58 -41
  16. data/lib/create_ruby_app/templates/Gemfile.erb +1 -3
  17. data/lib/create_ruby_app/templates/lib_file.erb +0 -2
  18. data/lib/create_ruby_app/templates/script_file.erb +0 -2
  19. data/lib/create_ruby_app/templates/spec_helper.erb +0 -2
  20. data/lib/create_ruby_app/version.rb +1 -3
  21. data/lib/create_ruby_app.rb +1 -3
  22. data/spec/integration/app_creation_spec.rb +170 -0
  23. data/spec/lib/create_ruby_app/actions/create_directories_spec.rb +1 -3
  24. data/spec/lib/create_ruby_app/actions/generate_files_spec.rb +13 -20
  25. data/spec/lib/create_ruby_app/actions/install_gems_spec.rb +1 -3
  26. data/spec/lib/create_ruby_app/actions/make_script_executable_spec.rb +1 -3
  27. data/spec/lib/create_ruby_app/actions/set_ruby_implementation_spec.rb +194 -0
  28. data/spec/lib/create_ruby_app/app_spec.rb +4 -4
  29. data/spec/lib/create_ruby_app/cli_spec.rb +112 -0
  30. data/spec/spec_helper.rb +6 -2
  31. metadata +52 -20
  32. data/lib/create_ruby_app/actions/null_action.rb +0 -9
data/LICENSE CHANGED
@@ -1,21 +1,13 @@
1
- MIT License
2
-
3
- Copyright (c) 2019 Mathias Jean Johansen
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Copyright (c) 2020 Mathias Jean Johansen
2
+
3
+ Permission to use, copy, modify, and distribute this software for any purpose
4
+ with or without fee is hereby granted, provided that the above copyright notice
5
+ and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
8
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
9
+ FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
10
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
11
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
12
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
13
+ PERFORMANCE OF THIS SOFTWARE.
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Create Ruby App
2
- [![Build Status](https://travis-ci.org/majjoha/create-ruby-app.svg)](https://travis-ci.org/majjoha/create-ruby-app)
2
+ ![CI](https://github.com/majjoha/create-ruby-app/workflows/CI/badge.svg)
3
3
  [![Gem Version](https://badge.fury.io/rb/create-ruby-app.svg)](http://badge.fury.io/rb/create-ruby-app)
4
4
 
5
5
  `create-ruby-app` is an opinionated tool for scaffolding Ruby applications
@@ -14,7 +14,7 @@ instead, and if you are building a gem, please take a look at the `bundle gem`
14
14
  command.
15
15
 
16
16
  ## Requirements
17
- * Ruby (version 2.6.2 or newer).
17
+ * Ruby (version 2.7.1 or newer).
18
18
 
19
19
  ## Installation
20
20
  ```
@@ -23,12 +23,12 @@ gem install create-ruby-app
23
23
 
24
24
  ## Usage
25
25
  ```
26
- create-ruby-app new NAME [--ruby RUBY] [--gems GEMS]
26
+ create-ruby-app new NAME [--ruby RUBY_VERSION] [--gems GEMS]
27
27
  ```
28
28
 
29
29
  ### Example
30
30
  ```
31
- create-ruby-app new my-app --gems sinatra,sequel --ruby ruby-2.6.1
31
+ create-ruby-app new my-app --gems sinatra,sequel --ruby ruby-2.7.1
32
32
  ```
33
33
 
34
34
  This will generate the following project structure with
@@ -54,4 +54,4 @@ Once the project is generated, it will run `bundle install` so you can start
54
54
  working.
55
55
 
56
56
  ## License
57
- See [LICENSE](https://github.com/majjoha/create-ruby-app/blob/master/LICENSE).
57
+ See [LICENSE](https://github.com/majjoha/create-ruby-app/blob/main/LICENSE).
@@ -0,0 +1,543 @@
1
+ # Pragmatic Refactoring Plan for create-ruby-app
2
+
3
+ ## Philosophy
4
+
5
+ For a small project like this, we'll focus on:
6
+ - **High-impact, low-effort changes first**
7
+ - **Maintaining backwards compatibility**
8
+ - **Keeping it simple - avoid over-engineering**
9
+ - **Each step is independently valuable and testable**
10
+
11
+ ---
12
+
13
+ ## Phase 1: Quick Wins (1-2 hours)
14
+
15
+ These changes are safe, require minimal testing, and provide immediate
16
+ value.
17
+
18
+ ### Step 1.1: Add logger gem dependency
19
+ **File:** `create_ruby_app.gemspec`
20
+
21
+ **Change:**
22
+ ```ruby
23
+ s.add_runtime_dependency "logger", "~> 1.6"
24
+ ```
25
+
26
+ **Why:** Fixes Ruby 3.5+ compatibility. Zero risk.
27
+
28
+ **Test:** Run tests, verify no warnings.
29
+
30
+ ---
31
+
32
+ ### Step 1.2: Remove empty class
33
+ **File:** `lib/create_ruby_app.rb`
34
+
35
+ **Change:** Delete lines 11-12 (the empty `CreateRubyApp::CreateRubyApp`
36
+ class)
37
+
38
+ **Why:** Dead code removal. Zero risk.
39
+
40
+ **Test:** Run tests, ensure nothing breaks.
41
+
42
+ ---
43
+
44
+ ### Step 1.3: Remove outdated gemspec date
45
+ **File:** `create_ruby_app.gemspec`
46
+
47
+ **Change:** Delete line 8 (`s.date = "2019-03-11"`)
48
+
49
+ **Why:** RubyGems sets this automatically. Zero risk.
50
+
51
+ **Test:** Build gem, verify metadata looks correct.
52
+
53
+ ---
54
+
55
+ ### Step 1.4: Add explanatory comment to CLI
56
+ **File:** `lib/create_ruby_app/cli.rb`
57
+
58
+ **Change:**
59
+ ```ruby
60
+ module Commands
61
+ # Extend (not include) required for Dry::CLI registry pattern
62
+ extend Dry::CLI::Registry
63
+ # ...
64
+ end
65
+ ```
66
+
67
+ **Why:** Better documentation. Zero risk.
68
+
69
+ **Test:** None needed.
70
+
71
+ ---
72
+
73
+ ## Phase 2: Error Handling (2-3 hours)
74
+
75
+ Add proper error handling without changing architecture.
76
+
77
+ ### Step 2.1: Create centralized error classes
78
+ **New file:** `lib/create_ruby_app/errors.rb`
79
+
80
+ ```ruby
81
+ module CreateRubyApp
82
+ class Error < StandardError; end
83
+
84
+ class NoRubyImplementationFoundError < Error; end
85
+ class DirectoryCreationError < Error; end
86
+ class FileGenerationError < Error; end
87
+ class GemInstallationError < Error; end
88
+ class ScriptExecutableError < Error; end
89
+ end
90
+ ```
91
+
92
+ **File:** `lib/create_ruby_app.rb` - Add:
93
+ ```ruby
94
+ require_relative "create_ruby_app/errors"
95
+ ```
96
+
97
+ **Why:** Centralized, consistent error handling.
98
+
99
+ **Test:** Ensure errors are loadable.
100
+
101
+ ---
102
+
103
+ ### Step 2.2: Add error handling to InstallGems
104
+ **File:** `lib/create_ruby_app/actions/install_gems.rb`
105
+
106
+ **Change:**
107
+ ```ruby
108
+ def call
109
+ Dir.chdir(app.name) do
110
+ success = system("bundle", "install")
111
+
112
+ unless success
113
+ raise GemInstallationError,
114
+ "Failed to install gems. Exit code: #{$?.exitstatus}"
115
+ end
116
+ end
117
+ rescue Errno::ENOENT
118
+ raise GemInstallationError,
119
+ "Bundler not found. Run: gem install bundler"
120
+ end
121
+ ```
122
+
123
+ **Why:** Prevent silent failures.
124
+
125
+ **Test:** Mock failing bundle install, verify error is raised.
126
+
127
+ ---
128
+
129
+ ### Step 2.3: Move existing error to errors.rb
130
+ **File:** `lib/create_ruby_app/actions/set_ruby_implementation.rb`
131
+
132
+ **Change:** Remove `NoRubyImplementationFoundError` class definition
133
+ (it's now in errors.rb).
134
+
135
+ **Why:** Consistency.
136
+
137
+ **Test:** Run tests, ensure error still works.
138
+
139
+ ---
140
+
141
+ ## Phase 3: Code Quality Improvements (2-3 hours)
142
+
143
+ Improve readability and maintainability without architectural changes.
144
+
145
+ ### Step 3.1: Simplify action interface
146
+ **File:** All action files
147
+
148
+ **Pattern to apply:**
149
+ ```ruby
150
+ # BEFORE:
151
+ class CreateDirectories
152
+ def initialize(app)
153
+ @app = app
154
+ end
155
+
156
+ def self.call(app)
157
+ new(app).call
158
+ end
159
+
160
+ def call
161
+ # ... implementation
162
+ end
163
+
164
+ attr_reader :app
165
+ end
166
+
167
+ # AFTER:
168
+ class CreateDirectories
169
+ def self.call(app)
170
+ # ... implementation (access app directly)
171
+ end
172
+ end
173
+ ```
174
+
175
+ **Files to change:**
176
+ - `lib/create_ruby_app/actions/create_directories.rb`
177
+ - `lib/create_ruby_app/actions/make_script_executable.rb`
178
+ - `lib/create_ruby_app/actions/install_gems.rb`
179
+
180
+ **Why:** Less boilerplate, clearer intent.
181
+
182
+ **Test:** Run all tests, ensure actions still work.
183
+
184
+ **Note:** Keep `GenerateFiles` and `SetRubyImplementation` as-is for
185
+ now (they have more complex state).
186
+
187
+ ---
188
+
189
+ ### Step 3.2: Extract gem formatting method
190
+ **File:** `lib/create_ruby_app/actions/generate_files.rb`
191
+
192
+ **Change:**
193
+ ```ruby
194
+ def gemfile
195
+ generate_file(
196
+ file: "Gemfile.erb",
197
+ locals: { gems: format_gems_for_gemfile(app.gems) }
198
+ )
199
+ end
200
+
201
+ private
202
+
203
+ def format_gems_for_gemfile(gems)
204
+ gems
205
+ .sort
206
+ .map { |gem| "gem \"#{gem}\"" }
207
+ .join("\n")
208
+ end
209
+ ```
210
+
211
+ **Why:** Testable, readable.
212
+
213
+ **Test:** Test `format_gems_for_gemfile` independently.
214
+
215
+ ---
216
+
217
+ ### Step 3.3: Make template constants private
218
+ **File:** `lib/create_ruby_app/actions/generate_files.rb`
219
+
220
+ **Change:**
221
+ ```ruby
222
+ TRIM_MODE = "<>"
223
+ TEMPLATES_DIR = "../templates"
224
+
225
+ private_constant :TRIM_MODE, :TEMPLATES_DIR
226
+ ```
227
+
228
+ **Why:** Better encapsulation.
229
+
230
+ **Test:** Ensure constants still work internally.
231
+
232
+ ---
233
+
234
+ ### Step 3.4: Replace empty lambda with explicit method
235
+ **File:** `lib/create_ruby_app/app.rb`
236
+
237
+ **Change:**
238
+ ```ruby
239
+ def run!
240
+ with_logger("Creating directories...", Actions::CreateDirectories)
241
+ with_logger(
242
+ "Setting Ruby implementations...",
243
+ Actions::SetRubyImplementation
244
+ )
245
+ with_logger("Generating files...", Actions::GenerateFiles)
246
+ with_logger("Making script executable...", Actions::MakeScriptExecutable)
247
+ with_logger("Installing gems...", Actions::InstallGems)
248
+ log_completion
249
+ end
250
+
251
+ private
252
+
253
+ # ... existing methods ...
254
+
255
+ def log_completion
256
+ logger.info("Happy hacking!")
257
+ end
258
+ ```
259
+
260
+ **Why:** Clear intent, no magic.
261
+
262
+ **Test:** Run app, verify completion message still appears.
263
+
264
+ ---
265
+
266
+ ## Phase 4: Path Management (2-3 hours)
267
+
268
+ Centralize path logic to reduce duplication.
269
+
270
+ ### Step 4.1: Add path helper methods to App
271
+ **File:** `lib/create_ruby_app/app.rb`
272
+
273
+ **Add these methods:**
274
+ ```ruby
275
+ def project_root
276
+ @project_root ||= Pathname.new(name)
277
+ end
278
+
279
+ def bin_dir
280
+ project_root.join("bin")
281
+ end
282
+
283
+ def bin_script_path
284
+ bin_dir.join(name)
285
+ end
286
+
287
+ def lib_dir
288
+ project_root.join("lib")
289
+ end
290
+
291
+ def lib_subdir
292
+ lib_dir.join(name)
293
+ end
294
+
295
+ def spec_lib_dir
296
+ project_root.join("spec", "lib", name)
297
+ end
298
+
299
+ def file_path(relative_path)
300
+ project_root.join(relative_path)
301
+ end
302
+ ```
303
+
304
+ **Why:** DRY, single source of truth for paths.
305
+
306
+ **Test:** Test each path method returns correct Pathname.
307
+
308
+ ---
309
+
310
+ ### Step 4.2: Update CreateDirectories to use path methods
311
+ **File:** `lib/create_ruby_app/actions/create_directories.rb`
312
+
313
+ **Change:**
314
+ ```ruby
315
+ def self.call(app)
316
+ [
317
+ app.bin_dir,
318
+ app.lib_subdir,
319
+ app.spec_lib_dir
320
+ ].each(&FileUtils.method(:mkdir_p))
321
+ end
322
+ ```
323
+
324
+ **Why:** Uses centralized path logic.
325
+
326
+ **Test:** Verify directories are still created correctly.
327
+
328
+ ---
329
+
330
+ ### Step 4.3: Update other actions to use path methods
331
+ **Files:**
332
+ - `lib/create_ruby_app/actions/make_script_executable.rb`:
333
+ ```ruby
334
+ def self.call(app)
335
+ FileUtils.chmod("+x", app.bin_script_path)
336
+ end
337
+ ```
338
+
339
+ - `lib/create_ruby_app/actions/generate_files.rb`:
340
+ ```ruby
341
+ def create_file(path:, content:)
342
+ File.write(app.file_path(path), content)
343
+ end
344
+ ```
345
+
346
+ - `lib/create_ruby_app/actions/install_gems.rb`:
347
+ ```ruby
348
+ def self.call(app)
349
+ Dir.chdir(app.project_root) do
350
+ # ... rest
351
+ end
352
+ end
353
+ ```
354
+
355
+ **Why:** Consistent path handling.
356
+
357
+ **Test:** Integration test - create full app, verify structure.
358
+
359
+ ---
360
+
361
+ ## Phase 5: Make SetRubyImplementation Pure (1-2 hours)
362
+
363
+ Remove mutation while keeping it simple.
364
+
365
+ ### Step 5.1: Change SetRubyImplementation to return version
366
+ **File:** `lib/create_ruby_app/actions/set_ruby_implementation.rb`
367
+
368
+ **Change:**
369
+ ```ruby
370
+ def call
371
+ return app.version if app.version
372
+
373
+ RUBY_IMPLEMENTATIONS.each do |ruby_implementation|
374
+ stdout, status = fetch_ruby_implementation(ruby_implementation)
375
+
376
+ if status.success? && !stdout.empty?
377
+ return transform_output_to_ruby_version(stdout)
378
+ end
379
+ end
380
+
381
+ raise NoRubyImplementationFoundError,
382
+ "No version of Ruby is found or provided"
383
+ end
384
+ ```
385
+
386
+ **Why:** Pure function, no side effects.
387
+
388
+ **Test:** Update tests to expect version string, not app object.
389
+
390
+ ---
391
+
392
+ ### Step 5.2: Update App#run! to handle version
393
+ **File:** `lib/create_ruby_app/app.rb`
394
+
395
+ **Change:**
396
+ ```ruby
397
+ def run!
398
+ with_logger("Creating directories...", Actions::CreateDirectories)
399
+
400
+ unless @version
401
+ @version = with_logger(
402
+ "Setting Ruby implementations...",
403
+ Actions::SetRubyImplementation
404
+ )
405
+ end
406
+
407
+ with_logger("Generating files...", Actions::GenerateFiles)
408
+ with_logger("Making script executable...", Actions::MakeScriptExecutable)
409
+ with_logger("Installing gems...", Actions::InstallGems)
410
+ log_completion
411
+ end
412
+
413
+ private
414
+
415
+ def with_logger(text, action)
416
+ logger.info(text)
417
+ action.call(self)
418
+ end
419
+ ```
420
+
421
+ **Why:** Explicit state management.
422
+
423
+ **Test:** Ensure version is set correctly, rest of flow works.
424
+
425
+ ---
426
+
427
+ ## Phase 6: Test Coverage (3-4 hours)
428
+
429
+ Bring coverage from 64.71% to 90%.
430
+
431
+ ### Step 6.1: Add error handling tests
432
+ Add tests for:
433
+ - `InstallGems` failure scenarios
434
+ - `CreateDirectories` permission errors
435
+ - `SetRubyImplementation` no Ruby found (already exists)
436
+
437
+ ### Step 6.2: Add integration tests
438
+ Add tests for:
439
+ - CLI.call integration
440
+ - Full app creation with various options
441
+
442
+ ### Step 6.3: Extract test helpers
443
+ **File:** `spec/support/ruby_implementation_stubber.rb`
444
+
445
+ ```ruby
446
+ module RubyImplementationStubber
447
+ def stub_ruby_implementations(except:, found_version:)
448
+ implementations = %w[ruby truffleruby jruby mruby rubinius]
449
+
450
+ implementations.each do |impl|
451
+ if impl == except
452
+ allow(Open3).to receive(:capture3).with("#{impl} -v")
453
+ .and_return([
454
+ found_version,
455
+ "",
456
+ instance_double(Process::Status, success?: true)
457
+ ])
458
+ else
459
+ allow(Open3).to receive(:capture3).with("#{impl} -v")
460
+ .and_return([
461
+ "",
462
+ "",
463
+ instance_double(Process::Status, success?: false)
464
+ ])
465
+ end
466
+ end
467
+ end
468
+ end
469
+ ```
470
+
471
+ **File:** `spec/spec_helper.rb` - Add:
472
+ ```ruby
473
+ require "support/ruby_implementation_stubber"
474
+
475
+ RSpec.configure do |config|
476
+ config.include RubyImplementationStubber
477
+ end
478
+ ```
479
+
480
+ **Why:** DRY in tests.
481
+
482
+ ---
483
+
484
+ ## What We're NOT Doing (and Why)
485
+
486
+ ### ❌ Action Pipeline Pattern
487
+ **Reason:** Over-engineering for 5 actions. Current approach is fine.
488
+
489
+ ### ❌ Value Objects (AppName, RubyVersion)
490
+ **Reason:** Primitive obsession isn't a problem at this scale. String
491
+ works fine.
492
+
493
+ ### ❌ Context Object / Dependency Injection
494
+ **Reason:** Actions accessing `app` directly is simple and clear for
495
+ this size.
496
+
497
+ ### ❌ Result Objects / Monads
498
+ **Reason:** Exceptions work well here. Don't need dry-monads complexity.
499
+
500
+ ### ❌ Separate TemplateRenderer Class
501
+ **Reason:** `GenerateFiles` is manageable as-is. Splitting adds little
502
+ value.
503
+
504
+ ### ❌ Decorator Pattern for Logging
505
+ **Reason:** `with_logger` method is simple and works. No need to
506
+ complicate.
507
+
508
+ ---
509
+
510
+ ## Summary
511
+
512
+ **Total Time:** ~12-15 hours of focused work
513
+ **Total Changes:** ~200-300 lines of code
514
+ **Risk Level:** Low (each phase is independently tested)
515
+
516
+ ### What This Achieves:
517
+ ✅ Ruby 3.5+ compatibility
518
+ ✅ Consistent error handling
519
+ ✅ Reduced boilerplate
520
+ ✅ Better path management (DRY)
521
+ ✅ Pure functions (SetRubyImplementation)
522
+ ✅ 90% test coverage
523
+ ✅ Cleaner, more maintainable code
524
+
525
+ ### What This Avoids:
526
+ ❌ Over-abstraction
527
+ ❌ Unnecessary complexity
528
+ ❌ Breaking changes
529
+ ❌ Framework-level refactoring
530
+
531
+ ---
532
+
533
+ ## Execution Order
534
+
535
+ 1. **Phase 1** (Quick Wins) - Do first, builds confidence
536
+ 2. **Phase 2** (Error Handling) - Important safety improvement
537
+ 3. **Phase 3** (Code Quality) - Makes codebase nicer to work with
538
+ 4. **Phase 4** (Path Management) - Biggest DRY improvement
539
+ 5. **Phase 5** (Pure Functions) - Core principle improvement
540
+ 6. **Phase 6** (Test Coverage) - Lock in all changes
541
+
542
+ Each phase can be done independently and committed separately. You can
543
+ stop after any phase and still have a better codebase.
data/bin/create-ruby-app CHANGED
@@ -1,7 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # frozen_string_literal: true
4
-
5
3
  require_relative "../lib/create_ruby_app"
6
4
 
7
- CreateRubyApp::CLI.start
5
+ CreateRubyApp::CLI.call
@@ -1,18 +1,26 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "fileutils"
4
2
  require "pathname"
5
3
 
6
4
  module CreateRubyApp
7
5
  module Actions
8
6
  class CreateDirectories
7
+ def initialize(app)
8
+ @app = app
9
+ end
10
+
9
11
  def self.call(app)
12
+ new(app).call
13
+ end
14
+
15
+ def call
10
16
  [
11
17
  Pathname.new("#{app.name}/bin"),
12
18
  Pathname.new("#{app.name}/lib/#{app.name}"),
13
19
  Pathname.new("#{app.name}/spec/lib/#{app.name}")
14
20
  ].each(&FileUtils.method(:mkdir_p))
15
21
  end
22
+
23
+ attr_reader :app
16
24
  end
17
25
  end
18
26
  end
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "erb"
4
2
  require "pathname"
5
3
 
@@ -38,7 +36,12 @@ module CreateRubyApp
38
36
  end
39
37
 
40
38
  def gemfile
41
- generate_file(file: "Gemfile.erb", locals: { gems: app.gems.sort })
39
+ generate_file(file: "Gemfile.erb", locals: {
40
+ gems: app
41
+ .gems
42
+ .sort
43
+ .map {|gem| "gem \"#{gem}\"" }.join("\n")
44
+ })
42
45
  end
43
46
 
44
47
  private
@@ -46,7 +49,7 @@ module CreateRubyApp
46
49
  attr_reader :app
47
50
 
48
51
  def generate_files
49
- files.each {|path, content| create_file(path: path, content: content) }
52
+ files.each { |path, content| create_file(path: path, content: content) }
50
53
  end
51
54
 
52
55
  def create_file(path:, content:)
@@ -1,11 +1,19 @@
1
- # frozen_string_literal: true
2
-
3
1
  module CreateRubyApp
4
2
  module Actions
5
3
  class InstallGems
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
6
8
  def self.call(app)
9
+ new(app).call
10
+ end
11
+
12
+ def call
7
13
  Dir.chdir(app.name) { system("bundle", "install") }
8
14
  end
15
+
16
+ attr_reader :app
9
17
  end
10
18
  end
11
19
  end