Module: FactoryBot::Instrumentation::AssetBundler
- Defined in:
- lib/factory_bot/instrumentation/asset_bundler.rb
Overview
A tiny, dependency-free replacement for Sprockets’ require_tree directive. It concatenates the JavaScript or CSS sources shipped with this engine into a single application.{js,css} asset so that the engine no longer needs an asset pipeline at runtime.
The bundles are regenerated in two situations:
-
During gem release, via the
bundle_assetsRake task which is hooked into rake build. -
On gem install / bundle install (including Git source installs in third-party applications), via the RubyGems extension shim at
ext/factory_bot_instrumentation/extconf.rb.
Constant Summary collapse
- ROOT_DIR =
Absolute path to the gem root (where the
appandlibfolders live), derived from this file’s location. File.('../../..', __dir__)
- KINDS =
Per-kind configuration. Each entry describes where the sources live, which extension to bundle, where to write the manifest and how to format the comments wrapping each chunk.
{ js: { source_dir: File.join( ROOT_DIR, 'app', 'assets', 'javascripts', 'factory_bot_instrumentation' ), output_name: 'application.js', extension: 'js', line_comment: '// %s', banner_format: :line }, css: { source_dir: File.join( ROOT_DIR, 'app', 'assets', 'stylesheets', 'factory_bot_instrumentation' ), output_name: 'application.css', extension: 'css', line_comment: '/* %s */', banner_format: :block } }.freeze
- BANNER_TEMPLATE =
Plain-text banner content, formatted per kind by
banner. The %<kind>s and %<source_rel>s placeholders are interpolated at render time viaformat. <<~TEXT !!! AUTO-GENERATED FILE - DO NOT EDIT !!! This file bundles every %<kind>s source under +%<source_rel>s/+ into a single asset. It is regenerated: * on `gem install` / `bundle install` (via a RubyGems extension hook), and * during gem release (via the `bundle_assets` Rake task). To rebuild it manually, run: $ bundle exec rake bundle_assets TEXT
Class Method Summary collapse
-
.banner(kind) ⇒ String
Render the auto-generation banner in the comment style of
kind. -
.bundle!(kind) ⇒ Array<String>
Build the bundle for the given
kindand write it to the corresponding manifest. -
.bundle_all! ⇒ Hash{Symbol => Array<String>}
Build every known asset kind in turn.
-
.chunk(kind, path) ⇒ String
Wrap a single source file with a comment that names its relative path.
-
.config(kind) ⇒ Hash
Look up the configuration for
kind, raising on unknown values. -
.kinds ⇒ Array<Symbol>
All asset kinds known to the bundler.
-
.relative_source(kind, file) ⇒ String
Path of
filerelative to its kind’s source directory, used in the per-chunk comment marker so the bundled output remains debuggable. -
.sources(kind) ⇒ Array<String>
All sources to include for
kind, sorted so the result is stable across platforms and filesystems.
Class Method Details
.banner(kind) ⇒ String
Render the auto-generation banner in the comment style of kind. JavaScript bundles get line comments (+// …+), CSS bundles get a single block comment (+/* … */+).
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 173 def (kind) conf = config(kind) text = format( BANNER_TEMPLATE, kind: conf[:extension].upcase, source_rel: conf[:source_dir].sub("#{ROOT_DIR}/", '') ) case conf[:banner_format] when :line lines = text.each_line .map { |l| format(conf[:line_comment], l.chomp).rstrip } .join("\n") "#{lines}\n" when :block body = text.each_line.map { |l| " * #{l.chomp}".rstrip }.join("\n") "/*\n#{body}\n */\n" end end |
.bundle!(kind) ⇒ Array<String>
Build the bundle for the given kind and write it to the corresponding manifest. The manifest itself is excluded from the input set so that re-runs are idempotent.
82 83 84 85 86 87 88 89 90 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 82 def bundle!(kind) conf = config(kind) files = sources(kind) File.write( File.join(conf[:source_dir], conf[:output_name]), (kind) + files.map { |f| chunk(kind, f) }.join ) files end |
.bundle_all! ⇒ Hash{Symbol => Array<String>}
Build every known asset kind in turn.
rubocop:disable Rails/IndexWith – because we’re
dependency-free in here
100 101 102 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 100 def bundle_all! kinds.to_h { |kind| [kind, bundle!(kind)] } end |
.chunk(kind, path) ⇒ String
Wrap a single source file with a comment that names its relative path. The returned snippet starts with a newline so that chunks concatenate cleanly under the banner.
157 158 159 160 161 162 163 164 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 157 def chunk(kind, path) conf = config(kind) body = File.read(path) body += "\n" unless body.end_with?("\n") marker = format(conf[:line_comment], ">>> #{relative_source(kind, path)}") "\n#{marker}\n#{body}" end |
.config(kind) ⇒ Hash
Look up the configuration for kind, raising on unknown values.
129 130 131 132 133 134 135 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 129 def config(kind) KINDS.fetch(kind) do raise ArgumentError, "Unknown asset kind #{kind.inspect}; expected one of " \ "#{KINDS.keys.inspect}" end end |
.kinds ⇒ Array<Symbol>
All asset kinds known to the bundler.
70 71 72 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 70 def kinds KINDS.keys end |
.relative_source(kind, file) ⇒ String
Path of file relative to its kind’s source directory, used in the per-chunk comment marker so the bundled output remains debuggable.
145 146 147 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 145 def relative_source(kind, file) file.sub("#{config(kind)[:source_dir]}/", '') end |
.sources(kind) ⇒ Array<String>
All sources to include for kind, sorted so the result is stable across platforms and filesystems. The manifest itself is excluded to avoid recursive inclusion.
113 114 115 116 117 118 119 120 |
# File 'lib/factory_bot/instrumentation/asset_bundler.rb', line 113 def sources(kind) conf = config(kind) output = File.(File.join(conf[:source_dir], conf[:output_name])) Dir.glob(File.join(conf[:source_dir], '**', "*.#{conf[:extension]}")) .reject { |path| File.(path) == output } .sort end |