Class: EnvStyle::Source

Inherits:
Object
  • Object
show all
Defined in:
lib/env_style/source.rb

Overview

Resolves and reads the source icon: the file whose bytes we tint and serve.

Resolution has two tiers:

1. Explicit +config.source+ (a Rails.root-relative path/Pathname, or a
 per-environment Hash) always wins.
2. Otherwise auto-discovery walks a conventional list, preferring SVG.

Nothing found never raises: it logs an actionable warning (outside production) and reports itself as not found.

Constant Summary collapse

AUTO_DISCOVERY =

Auto-discovery candidates, in priority order. SVG is preferred over raster.

%w[
  public/icon.svg
  public/icon.png
  public/favicon.svg
  public/favicon.ico
].freeze
SVG_SNIFF =

Sniffs SVG by content so a mislabeled extension still resolves correctly.

/<svg[\s>]/i
SVG_MEDIA_TYPE =
"image/svg+xml"
RASTER_SIGNATURES =

Raster media types keyed by their leading magic bytes, checked in order. WEBP is matched separately because its "WEBP" marker sits at byte 8, past the leading "RIFF" chunk id.

{
  "\x89PNG".b => "image/png",
  "\x00\x00\x01\x00".b => "image/vnd.microsoft.icon",
  "GIF8".b => "image/gif",
  "\xFF\xD8\xFF".b => "image/jpeg",
  "BM".b => "image/bmp"
}.freeze
DEFAULT_RASTER_MEDIA_TYPE =

Media type for an unrecognized raster. Conservative on purpose: the only raster engine route is .png, and browsers sniff the bytes themselves, so a wrong-but-harmless label never breaks the tab.

"image/png"
MISSING_MESSAGE =
"env_style: no source icon found — set EnvStyle.config.source"

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config: EnvStyle.config, root: self.class.rails_root, env_name: nil) ⇒ Source

Returns a new instance of Source.



48
49
50
51
52
# File 'lib/env_style/source.rb', line 48

def initialize(config: EnvStyle.config, root: self.class.rails_root, env_name: nil)
  @config = config
  @root = root && Pathname(root)
  @env_name = env_name
end

Class Method Details

.rails_rootObject



107
108
109
# File 'lib/env_style/source.rb', line 107

def self.rails_root
  Rails.root if defined?(Rails) && Rails.respond_to?(:root)
end

Instance Method Details

#content_typeObject

The true media type of the resolved source, sniffed from its bytes; nil when not found. SVG keeps the content-based sniff (a mislabeled extension still resolves), every other type is matched on its magic bytes, and an unrecognized raster falls back to DEFAULT_RASTER_MEDIA_TYPE. Unlike format, this distinguishes non-PNG rasters so untouched passthrough bytes are labeled with what they actually are.



93
94
95
96
97
98
# File 'lib/env_style/source.rb', line 93

def content_type
  return nil unless found?
  return SVG_MEDIA_TYPE if svg?

  raster_content_type
end

#digestObject

Content digest used to key caches and ETags; nil when not found.



101
102
103
104
105
# File 'lib/env_style/source.rb', line 101

def digest
  return nil unless found?

  Digest::SHA256.hexdigest(read)
end

#formatObject

:svg or :raster, decided by content; nil when not found.



73
74
75
76
77
# File 'lib/env_style/source.rb', line 73

def format
  return nil unless found?

  svg_content? ? :svg : :raster
end

#found?Boolean

Returns:

  • (Boolean)


61
62
63
# File 'lib/env_style/source.rb', line 61

def found?
  !path.nil?
end

#pathObject

The resolved icon path, or nil when nothing was found.



55
56
57
58
59
# File 'lib/env_style/source.rb', line 55

def path
  return @path if defined?(@path)

  @path = resolve_path
end

#raster?Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/env_style/source.rb', line 83

def raster?
  format == :raster
end

#readObject

Raw binary bytes of the source icon, or nil when not found.



66
67
68
69
70
# File 'lib/env_style/source.rb', line 66

def read
  return @read if defined?(@read)

  @read = path&.binread
end

#svg?Boolean

Returns:

  • (Boolean)


79
80
81
# File 'lib/env_style/source.rb', line 79

def svg?
  format == :svg
end