flash_unified 0.1.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.
@@ -0,0 +1,61 @@
1
+ require_relative 'lib/flash_unified/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "flash_unified"
5
+ spec.version = FlashUnified::VERSION
6
+ spec.authors = ["hiroaki"]
7
+ spec.email = ["176736+hiroaki@users.noreply.github.com"]
8
+
9
+ spec.summary = %q{Unified server/client flash messages for Rails with consistent templates}
10
+ spec.description = %q{Unified server/client flash messages for Rails with consistent templates—Turbo-ready, customizable, easy to integrate.}
11
+ spec.homepage = "https://github.com/hiroaki/flash-unified"
12
+ spec.license = "0BSD"
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.2.0")
14
+
15
+ #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/releases"
20
+ # Encourage MFA for publishing
21
+ spec.metadata["rubygems_mfa_required"] = "true"
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # Use a whitelist approach: explicitly include only the files and folders
25
+ # that are needed at runtime by the gem. This prevents accidentally
26
+ # packaging development-only files such as CI workflows, Appraisals and tests.
27
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
28
+ files = Dir[
29
+ "lib/**/*",
30
+ "app/**/*",
31
+ "config/locales/*",
32
+ "app/views/**/*",
33
+ "app/javascript/**/*",
34
+ "LICENSE",
35
+ "README.md",
36
+ "CHANGELOG.md",
37
+ "flash_unified.gemspec"
38
+ ].reject { |f| File.directory?(f) }
39
+ # Ensure version file is included
40
+ files << "lib/flash_unified/version.rb" unless files.include?("lib/flash_unified/version.rb")
41
+ files.uniq
42
+ end
43
+ spec.require_paths = ["lib"]
44
+
45
+ # Supported Rails versions: tested against 7.1, 7.2, 8.0
46
+ spec.add_dependency "rails", ">= 7.1"
47
+
48
+ # turbo-rails is used by host apps to provide Turbo/Hotwire integration; include
49
+ # it as a runtime dependency so the gem's JS + helpers work out of the box.
50
+ spec.add_dependency "turbo-rails", ">= 2.0"
51
+
52
+ #
53
+ spec.add_development_dependency "appraisal", ">= 2.5"
54
+ spec.add_development_dependency "capybara", ">= 3.40"
55
+ spec.add_development_dependency "cuprite", ">= 0.17"
56
+ spec.add_development_dependency "minitest", ">= 5.0"
57
+ spec.add_development_dependency "puma", ">= 7.0"
58
+ spec.add_development_dependency "rake", ">= 13.0"
59
+ spec.add_development_dependency "sprockets-rails", ">= 3.5"
60
+ spec.add_development_dependency "sqlite3", ">= 1.4"
61
+ end
@@ -0,0 +1,37 @@
1
+ module FlashUnified
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace FlashUnified
4
+
5
+ initializer "flash_unified.helpers" do
6
+ # Ensure the view helper is registered with ActionController so
7
+ # views in the host app (including the dummy app used for tests)
8
+ # can call helpers like `flash_container`.
9
+ # Use `config.to_prepare` so the helper is re-registered on each
10
+ # code reload in development.
11
+ config.to_prepare do
12
+ ActionController::Base.helper FlashUnified::ViewHelper
13
+ end
14
+ end
15
+
16
+ # Make the engine's `app/javascript` visible to asset pipelines like
17
+ # Propshaft or Sprockets by adding it to the assets paths and
18
+ # registering files for precompile if necessary.
19
+ initializer "flash_unified.assets" do |app|
20
+ js_path = root.join("app", "javascript").to_s
21
+ if app.config.respond_to?(:assets)
22
+ # Sprockets / Propshaft style
23
+ app.config.assets.paths << js_path
24
+ # Expose ES module entry points for production precompile
25
+ app.config.assets.precompile += %w[
26
+ flash_unified/flash_unified.js
27
+ flash_unified/auto.js
28
+ flash_unified/turbo_helpers.js
29
+ flash_unified/network_helpers.js
30
+ ]
31
+ else
32
+ # Fallback: still add to assets paths if available
33
+ app.config.assets.paths << js_path if app.config.respond_to?(:assets)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,147 @@
1
+ require "rails/generators"
2
+ require "rails/generators/base"
3
+
4
+ module FlashUnified
5
+ module Generators
6
+ class InstallGenerator < Rails::Generators::Base
7
+ desc "Copies FlashUnified javascript, view partials, locales and prints setup instructions (Importmap / asset pipeline)."
8
+
9
+ class_option :force, type: :boolean, default: false, desc: "Overwrite existing files"
10
+
11
+ # Print a clear start message so users see the generator run boundary.
12
+ # Using `say_status :run` follows the Rails generator convention (colored label).
13
+ # Print a start message once per generator run. An optional `note` will be
14
+ # appended to the message to provide context (e.g. "copy javascript").
15
+ def start_message(note = nil)
16
+ return if @flash_unified_started
17
+ message = "Installing FlashUnified"
18
+ message += " — #{note}" if note
19
+ say_status :run, message, :blue
20
+ @flash_unified_started = true
21
+ end
22
+
23
+ def copy_javascript
24
+ start_message("copy javascript")
25
+ installer = FlashUnified::Installer.new(source_root: File.expand_path('../../../../', __dir__), target_root: Dir.pwd, force: options[:force])
26
+ installer.copy_javascript do |status, path|
27
+ say_status status, display_path(path)
28
+ end
29
+ end
30
+
31
+ # View partials are copied into your host app so you can customize them.
32
+ def copy_view_partials
33
+ start_message("copy view partials")
34
+ installer = FlashUnified::Installer.new(source_root: File.expand_path('../../../../', __dir__), target_root: Dir.pwd, force: options[:force])
35
+ installer.copy_views do |status, path|
36
+ say_status status, display_path(path)
37
+ end
38
+ end
39
+
40
+ def copy_locales
41
+ start_message("copy locales")
42
+ installer = FlashUnified::Installer.new(source_root: File.expand_path('../../../../', __dir__), target_root: Dir.pwd, force: options[:force])
43
+ installer.copy_locales do |status, path|
44
+ say_status status, display_path(path)
45
+ end
46
+ end
47
+
48
+ def show_importmap_instructions
49
+ message = <<~MSG
50
+
51
+ === FlashUnified installation instructions ===
52
+
53
+ Importing the JavaScript
54
+ - Importmap: add to `config/importmap.rb`:
55
+
56
+ pin "flash_unified", to: "flash_unified/flash_unified.js"
57
+ pin "flash_unified/auto", to: "flash_unified/auto.js"
58
+ pin "flash_unified/turbo_helpers", to: "flash_unified/turbo_helpers.js"
59
+ pin "flash_unified/network_helpers", to: "flash_unified/network_helpers.js"
60
+
61
+ Quick start (auto init):
62
+
63
+ Importing `flash_unified/auto` sets up Turbo listeners and triggers an initial render.
64
+
65
+ import "flash_unified/auto";
66
+ // Configure via <html data-flash-unified-*>:
67
+ // data-flash-unified-auto-init="false" (opt-out)
68
+ // data-flash-unified-enable-network-errors="true" (install Turbo network error listeners)
69
+
70
+ Manual control:
71
+
72
+ import { renderFlashMessages, appendMessageToStorage } from "flash_unified";
73
+ import { installTurboRenderListeners } from "flash_unified/turbo_helpers";
74
+ installTurboRenderListeners();
75
+
76
+ Network helpers (optional, framework-agnostic):
77
+
78
+ import { notifyNetworkError, notifyHttpError } from "flash_unified/network_helpers";
79
+ // notifyNetworkError();
80
+ // notifyHttpError(413);
81
+
82
+ - Asset pipeline (Propshaft / Sprockets): the engine adds its `app/javascript` to the asset paths; add modulepreload links and an inline importmap in your layout's `<head>` and import the bare specifier.
83
+
84
+ <link rel="modulepreload" href="<%= asset_path('flash_unified/flash_unified.js') %>">
85
+ <link rel="modulepreload" href="<%= asset_path('flash_unified/network_helpers.js') %>">
86
+ <link rel="modulepreload" href="<%= asset_path('flash_unified/turbo_helpers.js') %>">
87
+ <link rel="modulepreload" href="<%= asset_path('flash_unified/auto.js') %>">
88
+ <script type="importmap">
89
+ {
90
+ "imports": {
91
+ "flash_unified": "<%= asset_path('flash_unified/flash_unified.js') %>",
92
+ "flash_unified/auto": "<%= asset_path('flash_unified/auto.js') %>",
93
+ "flash_unified/turbo_helpers": "<%= asset_path('flash_unified/turbo_helpers.js') %>",
94
+ "flash_unified/network_helpers": "<%= asset_path('flash_unified/network_helpers.js') %>"
95
+ }
96
+ }
97
+ </script>
98
+ <script type="module">
99
+ import "flash_unified/auto";
100
+ </script>
101
+
102
+ Remove the `import "flash_unified/auto";` line if you don't want automatic initialization.
103
+
104
+ How to place partials in your layout
105
+ - The gem's view helpers render engine partials. After running this generator you'll have the partials available under `app/views/flash_unified` and can customize them as needed.
106
+
107
+ Recommended layout snippet (inside `<body>`, global helpers):
108
+
109
+ <%= flash_general_error_messages %>
110
+ <%= flash_global_storage %>
111
+ <%= flash_templates %>
112
+
113
+ Place the visible container wherever messages should appear:
114
+
115
+ <%= flash_container %>
116
+
117
+ Embed per-response storage inside content (e.g. Turbo Frame responses):
118
+
119
+ <%= flash_storage %>
120
+
121
+ Documentation
122
+ - For full details and customization guidance, see README.md / README.ja.md in the gem.
123
+
124
+ MSG
125
+
126
+ say message
127
+ end
128
+
129
+ private
130
+
131
+ # Return a user-friendly path for display in generator output. If the
132
+ # provided path is under the current working directory (Rails root), show
133
+ # it as a relative path; otherwise show the original path.
134
+ def display_path(path)
135
+ path = Pathname.new(path.to_s)
136
+ begin
137
+ root = Pathname.new(Dir.pwd)
138
+ relative = path.relative_path_from(root)
139
+ relative.to_s
140
+ rescue ArgumentError
141
+ # Path not under Dir.pwd — fall back to full path
142
+ path.to_s
143
+ end
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,95 @@
1
+ require 'fileutils'
2
+ require 'pathname'
3
+
4
+ module FlashUnified
5
+ # Pure-Ruby installer logic extracted from the generator so it can be
6
+ # unit-tested without loading Rails. Responsible for copying javascript,
7
+ # view partials and locale files from the gem source into a target app.
8
+ class Installer
9
+ attr_reader :source_root, :target_root, :force
10
+
11
+ def initialize(source_root:, target_root:, force: false)
12
+ @source_root = Pathname.new(source_root)
13
+ @target_root = Pathname.new(target_root)
14
+ @force = !!force
15
+ end
16
+
17
+ def copy_javascript(&block)
18
+ src = source_root.join('app', 'javascript', 'flash_unified')
19
+ dst = target_root.join('app', 'javascript', 'flash_unified')
20
+ copy_tree(src, dst, &block)
21
+ end
22
+
23
+ def copy_views(&block)
24
+ src_dir = source_root.join('app', 'views', 'flash_unified')
25
+ dst_dir = target_root.join('app', 'views', 'flash_unified')
26
+ files = %w[
27
+ _templates.html.erb
28
+ _storage.html.erb
29
+ _global_storage.html.erb
30
+ _container.html.erb
31
+ _general_error_messages.html.erb
32
+ ]
33
+ copy_files(files, src_dir, dst_dir, &block)
34
+ end
35
+
36
+ def copy_locales(&block)
37
+ src_dir = source_root.join('config', 'locales')
38
+ dst_dir = target_root.join('config', 'locales')
39
+ FileUtils.mkdir_p(dst_dir) unless dst_dir.exist?
40
+ files = Dir.glob(src_dir.join('*.yml')).map { |p| File.basename(p) }
41
+ copy_files(files, src_dir, dst_dir, &block)
42
+ end
43
+
44
+ private
45
+
46
+ def copy_tree(src, dst, &block)
47
+ raise "source missing: #{src}" unless src.directory?
48
+ status = :skip
49
+ if dst.exist?
50
+ if force
51
+ FileUtils.rm_rf(dst)
52
+ FileUtils.mkdir_p(dst)
53
+ FileUtils.cp_r(File.join(src, '.'), dst)
54
+ status = :overwrite
55
+ else
56
+ status = :skip
57
+ end
58
+ else
59
+ FileUtils.mkdir_p(dst)
60
+ FileUtils.cp_r(File.join(src, '.'), dst)
61
+ status = :create
62
+ end
63
+ # Report status for the whole directory
64
+ block.call(status, dst) if block
65
+ status
66
+ end
67
+
68
+ def copy_files(list, src_dir, dst_dir, &block)
69
+ raise "source missing: #{src_dir}" unless src_dir.directory?
70
+ FileUtils.mkdir_p(dst_dir) unless dst_dir.exist?
71
+ status = :skip
72
+ list.each do |fname|
73
+ src = src_dir.join(fname)
74
+ next unless src.file?
75
+ dst = dst_dir.join(fname)
76
+ file_status = :skip
77
+ if dst.exist?
78
+ if force
79
+ FileUtils.cp(src, dst)
80
+ file_status = :overwrite
81
+ else
82
+ file_status = :skip
83
+ end
84
+ else
85
+ FileUtils.cp(src, dst)
86
+ file_status = :create
87
+ end
88
+ block.call(file_status, dst) if block
89
+ # Track overall status for return value
90
+ status = file_status if file_status == :create || (file_status == :overwrite && status != :create)
91
+ end
92
+ status
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,13 @@
1
+ require "rails/railtie"
2
+
3
+ module FlashUnified
4
+ class Railtie < Rails::Railtie
5
+ # Ensure the gem's generators are required so `rails generate` lists
6
+ # them when the gem is installed into a host application. Using the
7
+ # `generators` block defers the `require` until generator loading
8
+ # time and avoids loading Rails-only code during normal gem require.
9
+ generators do
10
+ require_relative "generators/install/install_generator"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module FlashUnified
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,19 @@
1
+ require "flash_unified/version"
2
+
3
+ # Load the engine when running inside Rails. Using `require` (library
4
+ # path) is the conventional approach for gems; guard with
5
+ # `defined?(Rails)` so loading the gem in non-Rails contexts won't
6
+ # attempt to load the engine.
7
+ require "flash_unified/engine" if defined?(Rails)
8
+
9
+ # Load Railtie to register generators when running `rails generate`.
10
+ require "flash_unified/railtie" if defined?(Rails)
11
+
12
+ # Installer is a small, framework-agnostic helper used by the generator
13
+ # and needs to be available when running generator code outside of Rails.
14
+ require "flash_unified/installer"
15
+
16
+ module FlashUnified
17
+ class Error < StandardError; end
18
+ # Your code goes here...
19
+ end
metadata ADDED
@@ -0,0 +1,209 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: flash_unified
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - hiroaki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2025-10-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '7.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: turbo-rails
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: appraisal
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: capybara
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '3.40'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '3.40'
69
+ - !ruby/object:Gem::Dependency
70
+ name: cuprite
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0.17'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0.17'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '5.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '5.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: puma
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '7.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '7.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '13.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '13.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: sprockets-rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '3.5'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '3.5'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sqlite3
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '1.4'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '1.4'
153
+ description: Unified server/client flash messages for Rails with consistent templates—Turbo-ready,
154
+ customizable, easy to integrate.
155
+ email:
156
+ - 176736+hiroaki@users.noreply.github.com
157
+ executables: []
158
+ extensions: []
159
+ extra_rdoc_files: []
160
+ files:
161
+ - LICENSE
162
+ - README.md
163
+ - app/helpers/flash_unified/view_helper.rb
164
+ - app/javascript/flash_unified/auto.js
165
+ - app/javascript/flash_unified/flash_unified.js
166
+ - app/javascript/flash_unified/network_helpers.js
167
+ - app/javascript/flash_unified/turbo_helpers.js
168
+ - app/views/flash_unified/_container.html.erb
169
+ - app/views/flash_unified/_general_error_messages.html.erb
170
+ - app/views/flash_unified/_global_storage.html.erb
171
+ - app/views/flash_unified/_storage.html.erb
172
+ - app/views/flash_unified/_templates.html.erb
173
+ - config/locales/http_status_messages.en.yml
174
+ - config/locales/http_status_messages.ja.yml
175
+ - flash_unified.gemspec
176
+ - lib/flash_unified.rb
177
+ - lib/flash_unified/engine.rb
178
+ - lib/flash_unified/generators/install/install_generator.rb
179
+ - lib/flash_unified/installer.rb
180
+ - lib/flash_unified/railtie.rb
181
+ - lib/flash_unified/version.rb
182
+ homepage: https://github.com/hiroaki/flash-unified
183
+ licenses:
184
+ - 0BSD
185
+ metadata:
186
+ homepage_uri: https://github.com/hiroaki/flash-unified
187
+ source_code_uri: https://github.com/hiroaki/flash-unified
188
+ changelog_uri: https://github.com/hiroaki/flash-unified/releases
189
+ rubygems_mfa_required: 'true'
190
+ post_install_message:
191
+ rdoc_options: []
192
+ require_paths:
193
+ - lib
194
+ required_ruby_version: !ruby/object:Gem::Requirement
195
+ requirements:
196
+ - - ">="
197
+ - !ruby/object:Gem::Version
198
+ version: 3.2.0
199
+ required_rubygems_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ requirements: []
205
+ rubygems_version: 3.4.19
206
+ signing_key:
207
+ specification_version: 4
208
+ summary: Unified server/client flash messages for Rails with consistent templates
209
+ test_files: []