hanami-sprockets 0.1.0 → 0.2.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: c506dbf07d8b95e741306b6511182bc1428913b4f081f09a5727143de9f27ba3
4
- data.tar.gz: d307f243f6ea655eeeafbddf4b326cd75307ea25321b75215a933563543a456a
3
+ metadata.gz: 423164431eeaf7e1c3809ab78f15b9322b458644726fb505f610be3db9b03981
4
+ data.tar.gz: 341808d42f74242bd36cb147c575752054e5e4f4feefdac6d3b0cac1e5016c43
5
5
  SHA512:
6
- metadata.gz: cff9adcbec8df4c221ab3df289b7f33d8065dc12e98f6cb959c0e7828ea1cc01e9208ebba5c7f18d14338244b55160b04fde1e6fabd183b5a2b3beae26163815
7
- data.tar.gz: cddf52b5cd2a4c5c968c3d11504f19bae75249239685f4a92664ea93264ed410f2ac625ce1f0954c69759f302bec0d21cfa9b03a055b521c3568b9fe40609f5d
6
+ metadata.gz: a775a3d136a96f5abeed83864d19f3e7b72461b528f2e1ab4af10e8559cbbac2a9fc02f77a1060e7d0c8a7ebb78518c59bc52518e8d95c1edf26e3466c1ca0d3
7
+ data.tar.gz: 6969306f684ae65c55b8f6c3464152c00cf3514d21164a7d9dc1686fc62ef44e51ac50d9cfc651416a0dc82c057a2191d34b3c0153227db01affe44b85633317
data/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.2.0] - 2025-10-01
8
+ ### Added
9
+ - CLI commands: `hanami-sprockets compile` and `hanami-sprockets watch`
10
+ - Hanami CLI integration: `hanami assets compile` and `hanami assets watch`
11
+ - Asset watch mode with file monitoring and auto-recompilation
12
+
13
+ ### Fixed
14
+ - CSS custom properties test failures
15
+
7
16
  ## [0.1.0] - 2025-09-29
8
17
  ### Added
9
18
  - Initial release
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Hanami::Sprockets
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/hanami-sprockets.svg)](https://badge.fury.io/rb/hanami-sprockets)
4
+
3
5
  Drop-in replacement for hanami-assets that uses Sprockets (like Rails) instead of npm/Node.js.
4
6
 
5
7
  If you want the Rails asset pipeline in your Hanami app without dealing with npm, this is for you.
@@ -24,7 +26,7 @@ gem 'hanami-sprockets'
24
26
  And then execute:
25
27
 
26
28
  ```bash
27
- $ bundle install
29
+ bundle install
28
30
  ```
29
31
 
30
32
  ## Basic Usage
@@ -52,7 +54,7 @@ assets = Hanami::Assets.new(
52
54
 
53
55
  Follow Rails conventions:
54
56
 
55
- ```
57
+ ```text
56
58
  app/
57
59
  ├── assets/
58
60
  │ ├── stylesheets/
@@ -153,6 +155,63 @@ manifest = assets.precompile("/path/to/public/assets")
153
155
  puts "Compiled assets:", manifest.assets.keys
154
156
  ```
155
157
 
158
+ ### Command Line Interface
159
+
160
+ The gem includes CLI commands similar to Hanami's asset commands:
161
+
162
+ #### Compile Assets
163
+
164
+ Compile assets for production deployment:
165
+
166
+ ```bash
167
+ bundle exec hanami-sprockets compile
168
+ ```
169
+
170
+ With custom output directory:
171
+
172
+ ```bash
173
+ bundle exec hanami-sprockets compile -o public/dist
174
+ ```
175
+
176
+ #### Watch Assets
177
+
178
+ Watch assets for changes during development:
179
+
180
+ ```bash
181
+ bundle exec hanami-sprockets watch
182
+ ```
183
+
184
+ The watch command monitors your asset directories for changes and automatically recompiles when files are modified. Requires the `listen` gem to be available.
185
+
186
+ #### CLI Options
187
+
188
+ ```bash
189
+ Usage: hanami-sprockets [COMMAND] [OPTIONS]
190
+
191
+ Commands:
192
+ compile Compile assets for production
193
+ watch Watch assets for changes and recompile
194
+
195
+ Options:
196
+ -r, --root ROOT Application root directory
197
+ -o, --output OUTPUT Output directory for compiled assets
198
+ -h, --help Show help message
199
+ ```
200
+
201
+ ### Integration with Hanami CLI
202
+
203
+ When used within a Hanami application, hanami-sprockets provides command classes that can be automatically discovered by Hanami's CLI system. This allows you to use:
204
+
205
+ ```bash
206
+ # Instead of hanami-sprockets compile
207
+ hanami assets compile
208
+
209
+ # Instead of hanami-sprockets watch
210
+ hanami assets watch
211
+ ```
212
+
213
+ These commands integrate seamlessly with Hanami's application structure and automatically discover your app's configuration. The gem provides compatible command classes in the `Hanami::CLI::Commands::App::Assets` namespace that follow Hanami's CLI conventions.
214
+
156
215
  ## Advanced Configuration
157
216
 
158
217
  ```ruby
@@ -209,7 +268,7 @@ Main class for asset management.
209
268
 
210
269
  Represents a single asset.
211
270
 
212
- #### Methods
271
+ #### Asset Methods
213
272
 
214
273
  - `#url` - Full URL to asset
215
274
  - `#path` - Path to asset (without base URL)
@@ -221,7 +280,7 @@ Represents a single asset.
221
280
 
222
281
  Template helpers for generating asset HTML tags.
223
282
 
224
- #### Methods
283
+ #### Helper Methods
225
284
 
226
285
  - `stylesheet_tag(*sources, **options)` - Generate `<link>` tags
227
286
  - `javascript_tag(*sources, **options)` - Generate `<script>` tags
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "hanami/sprockets"
6
+ require "hanami/sprockets/cli"
7
+
8
+ Hanami::Assets::CLI.start(ARGV)
@@ -33,4 +33,5 @@ Gem::Specification.new do |spec|
33
33
  spec.add_development_dependency "rack-test", "~> 1.1"
34
34
  spec.add_development_dependency "dry-configurable", "~> 1.1"
35
35
  spec.add_development_dependency "dry-inflector", "~> 1.0"
36
+ spec.add_development_dependency "listen", "~> 3.8"
36
37
  end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pathname"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module App
9
+ module Assets
10
+ class Command
11
+ def initialize(out: $stdout)
12
+ @out = out
13
+ end
14
+
15
+ def call(app: nil)
16
+ assets = create_assets_instance(app)
17
+ output_dir = default_output_dir(app)
18
+
19
+ execute_assets_command(assets, output_dir)
20
+ end
21
+
22
+ protected
23
+
24
+ attr_reader :out
25
+
26
+ def create_assets_instance(app)
27
+ root = app ? app.root : Pathname.pwd
28
+ config = Hanami::Assets::Config.new(digest: true)
29
+ Hanami::Assets.new(config: config, root: root.to_s)
30
+ end
31
+
32
+ def default_output_dir(app)
33
+ root = app ? app.root : Pathname.pwd
34
+ root.join("public", "assets").to_s
35
+ end
36
+
37
+ def execute_assets_command(assets, output_dir)
38
+ raise NotImplementedError, "Subclasses must implement #execute_assets_command"
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "command"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module App
9
+ module Assets
10
+ class Compile < Command
11
+ def execute_assets_command(assets, output_dir)
12
+ out.puts "Compiling assets using Sprockets..."
13
+
14
+ manifest = assets.precompile(output_dir)
15
+
16
+ out.puts "Assets compiled successfully:"
17
+ manifest.assets.each do |logical_path, digest_path|
18
+ out.puts " #{logical_path} -> #{digest_path}"
19
+ end
20
+
21
+ out.puts "Output directory: #{output_dir}"
22
+ rescue => e
23
+ out.puts "Error compiling assets: #{e.message}"
24
+ raise
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "command"
4
+
5
+ module Hanami
6
+ module CLI
7
+ module Commands
8
+ module App
9
+ module Assets
10
+ class Watch < Command
11
+ def execute_assets_command(assets, output_dir)
12
+ out.puts "Starting Sprockets asset watch mode..."
13
+ out.puts "Press Ctrl+C to stop"
14
+
15
+ require "listen"
16
+
17
+ asset_paths = find_asset_paths(assets)
18
+
19
+ if asset_paths.empty?
20
+ out.puts "No asset directories found. Looking for:"
21
+ %w[app/assets lib/assets vendor/assets].each do |path|
22
+ out.puts " #{path}"
23
+ end
24
+ return
25
+ end
26
+
27
+ out.puts "Watching directories:"
28
+ asset_paths.each { |path| out.puts " #{path}" }
29
+
30
+ listener = Listen.to(*asset_paths, only: /\.(css|js|scss|sass|coffee|erb)$/) do |modified, added, removed|
31
+ out.puts "\nChanges detected:"
32
+ (modified + added + removed).each { |file| out.puts " #{file}" }
33
+
34
+ begin
35
+ out.puts "Recompiling assets..."
36
+ assets.precompile(output_dir)
37
+ out.puts "Assets recompiled successfully"
38
+ rescue => e
39
+ out.puts "Error recompiling assets: #{e.message}"
40
+ end
41
+ end
42
+
43
+ listener.start
44
+
45
+ trap("INT") { listener.stop; exit }
46
+
47
+ sleep
48
+ rescue LoadError
49
+ out.puts "Error: 'listen' gem is required for watch mode."
50
+ out.puts "Add 'gem \"listen\"' to your Gemfile and run 'bundle install'"
51
+ raise
52
+ rescue => e
53
+ out.puts "Error in watch mode: #{e.message}"
54
+ raise
55
+ end
56
+
57
+ private
58
+
59
+ def find_asset_paths(assets)
60
+ root = Pathname(assets.root)
61
+ paths = []
62
+ %w[app/assets lib/assets vendor/assets].each do |relative_path|
63
+ path = root.join(relative_path)
64
+ paths << path.to_s if path.exist?
65
+ end
66
+ paths
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "assets/compile"
4
+ require_relative "assets/watch"
5
+
6
+ module Hanami
7
+ module CLI
8
+ module Commands
9
+ module App
10
+ module Assets
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,174 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "optparse"
4
+ require "pathname"
5
+ require "fileutils"
6
+
7
+ module Hanami
8
+ class Assets
9
+ class CLI
10
+ class << self
11
+ def start(args)
12
+ new(args).call
13
+ end
14
+ end
15
+
16
+ def initialize(args)
17
+ @args = args
18
+ @command = nil
19
+ @options = {}
20
+ @root = Pathname.pwd
21
+ end
22
+
23
+ def call
24
+ parse_options
25
+
26
+ case @command
27
+ when "compile"
28
+ compile
29
+ when "watch"
30
+ watch
31
+ else
32
+ show_help
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ def parse_options
39
+ parser = OptionParser.new do |opts|
40
+ opts.banner = "Usage: hanami-sprockets [COMMAND] [OPTIONS]"
41
+ opts.separator ""
42
+ opts.separator "Commands:"
43
+ opts.separator " compile Compile assets for production"
44
+ opts.separator " watch Watch assets for changes and recompile"
45
+ opts.separator ""
46
+ opts.separator "Options:"
47
+
48
+ opts.on("-r", "--root ROOT", "Application root directory") do |root|
49
+ @options[:root] = root
50
+ @root = Pathname(root)
51
+ end
52
+
53
+ opts.on("-o", "--output OUTPUT", "Output directory for compiled assets") do |output|
54
+ @options[:output] = output
55
+ end
56
+
57
+ opts.on("-h", "--help", "Show this help message") do
58
+ puts opts
59
+ exit
60
+ end
61
+ end
62
+
63
+ begin
64
+ parser.parse!(@args)
65
+ @command = @args.shift
66
+ rescue OptionParser::InvalidOption => e
67
+ puts "Error: #{e.message}"
68
+ puts parser
69
+ exit(1)
70
+ end
71
+ end
72
+
73
+ def compile
74
+ puts "Compiling assets..."
75
+
76
+ output_dir = @options[:output] || @root.join("public", "assets").to_s
77
+
78
+ assets = create_assets_instance
79
+ manifest = assets.precompile(output_dir)
80
+
81
+ puts "Assets compiled successfully:"
82
+ manifest.assets.each do |logical_path, digest_path|
83
+ puts " #{logical_path} -> #{digest_path}"
84
+ end
85
+
86
+ puts "Output directory: #{output_dir}"
87
+ rescue => e
88
+ puts "Error compiling assets: #{e.message}"
89
+ exit(1)
90
+ end
91
+
92
+ def watch
93
+ puts "Starting asset watch mode..."
94
+ puts "Press Ctrl+C to stop"
95
+
96
+ require "listen"
97
+
98
+ assets = create_assets_instance
99
+ asset_paths = find_asset_paths
100
+
101
+ if asset_paths.empty?
102
+ puts "No asset directories found. Looking for:"
103
+ %w[app/assets lib/assets vendor/assets].each do |path|
104
+ puts " #{@root.join(path)}"
105
+ end
106
+ exit(1)
107
+ end
108
+
109
+ puts "Watching directories:"
110
+ asset_paths.each { |path| puts " #{path}" }
111
+
112
+ listener = Listen.to(*asset_paths, only: /\.(css|js|scss|sass|coffee|erb)$/) do |modified, added, removed|
113
+ puts "\nChanges detected:"
114
+ (modified + added + removed).each { |file| puts " #{file}" }
115
+
116
+ begin
117
+ puts "Recompiling assets..."
118
+ output_dir = @options[:output] || @root.join("public", "assets").to_s
119
+ assets.precompile(output_dir)
120
+ puts "Assets recompiled successfully"
121
+ rescue => e
122
+ puts "Error recompiling assets: #{e.message}"
123
+ end
124
+ end
125
+
126
+ listener.start
127
+
128
+ trap("INT") { listener.stop; exit }
129
+
130
+ sleep
131
+ rescue LoadError
132
+ puts "Error: 'listen' gem is required for watch mode."
133
+ puts "Add 'gem \"listen\"' to your Gemfile and run 'bundle install'"
134
+ exit(1)
135
+ rescue => e
136
+ puts "Error in watch mode: #{e.message}"
137
+ exit(1)
138
+ end
139
+
140
+ def show_help
141
+ puts "Usage: hanami-sprockets [COMMAND] [OPTIONS]"
142
+ puts ""
143
+ puts "Commands:"
144
+ puts " compile Compile assets for production"
145
+ puts " watch Watch assets for changes and recompile"
146
+ puts ""
147
+ puts "Options:"
148
+ puts " -r, --root ROOT Application root directory"
149
+ puts " -o, --output OUTPUT Output directory for compiled assets"
150
+ puts " -h, --help Show this help message"
151
+ puts ""
152
+ puts "Examples:"
153
+ puts " hanami-sprockets compile"
154
+ puts " hanami-sprockets compile -o public/assets"
155
+ puts " hanami-sprockets watch"
156
+ puts " hanami-sprockets watch -r /path/to/app"
157
+ end
158
+
159
+ def create_assets_instance
160
+ config = Hanami::Assets::Config.new(digest: true)
161
+ Hanami::Assets.new(config: config, root: @root.to_s)
162
+ end
163
+
164
+ def find_asset_paths
165
+ paths = []
166
+ %w[app/assets lib/assets vendor/assets].each do |relative_path|
167
+ path = @root.join(relative_path)
168
+ paths << path.to_s if path.exist?
169
+ end
170
+ paths
171
+ end
172
+ end
173
+ end
174
+ end
@@ -4,6 +4,6 @@ module Hanami
4
4
  class Assets
5
5
  # @api private
6
6
  # @since 0.1.0
7
- VERSION = "0.1.0"
7
+ VERSION = "0.2.0"
8
8
  end
9
9
  end
@@ -22,7 +22,9 @@ module Hanami
22
22
  loader.ignore(
23
23
  "#{root}/hanami-sprockets.rb",
24
24
  "#{root}/hanami/sprockets/version.rb",
25
- "#{root}/hanami/sprockets/errors.rb"
25
+ "#{root}/hanami/sprockets/errors.rb",
26
+ "#{root}/hanami/sprockets/cli.rb",
27
+ "#{root}/hanami/cli"
26
28
  )
27
29
  loader.enable_reloading if loader.respond_to?(:enable_reloading)
28
30
  loader.inflector = Zeitwerk::GemInflector.new("#{root}/hanami-sprockets.rb")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
@@ -183,22 +183,43 @@ dependencies:
183
183
  - - "~>"
184
184
  - !ruby/object:Gem::Version
185
185
  version: '1.0'
186
+ - !ruby/object:Gem::Dependency
187
+ name: listen
188
+ requirement: !ruby/object:Gem::Requirement
189
+ requirements:
190
+ - - "~>"
191
+ - !ruby/object:Gem::Version
192
+ version: '3.8'
193
+ type: :development
194
+ prerelease: false
195
+ version_requirements: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: '3.8'
186
200
  description: Alternative to hanami-assets that uses Sprockets for asset compilation
187
201
  and management, compatible with existing Sprockets gems
188
202
  email:
189
203
  - andrewnez@gmail.com
190
- executables: []
204
+ executables:
205
+ - hanami-sprockets
191
206
  extensions: []
192
207
  extra_rdoc_files: []
193
208
  files:
194
209
  - CHANGELOG.md
195
210
  - LICENSE.md
196
211
  - README.md
212
+ - bin/hanami-sprockets
197
213
  - hanami-sprockets.gemspec
198
214
  - lib/hanami-sprockets.rb
215
+ - lib/hanami/cli/commands/app/assets.rb
216
+ - lib/hanami/cli/commands/app/assets/command.rb
217
+ - lib/hanami/cli/commands/app/assets/compile.rb
218
+ - lib/hanami/cli/commands/app/assets/watch.rb
199
219
  - lib/hanami/sprockets.rb
200
220
  - lib/hanami/sprockets/asset.rb
201
221
  - lib/hanami/sprockets/base_url.rb
222
+ - lib/hanami/sprockets/cli.rb
202
223
  - lib/hanami/sprockets/config.rb
203
224
  - lib/hanami/sprockets/errors.rb
204
225
  - lib/hanami/sprockets/helpers.rb