Class: Tuile::ThemeDef

Inherits:
Object
  • Object
show all
Defined in:
lib/tuile/theme_def.rb

Overview

An app’s theme definition: the Theme pair covering both terminal appearances. Screen keeps one at Screen#theme_def (defaulting to DEFAULT) and picks the member matching the detected background at startup and on every OS appearance flip (mode 2031) — so a custom definition survives the user toggling light/dark, where a bare Screen#theme= assignment would be replaced.

APP_THEME = Tuile::ThemeDef.new(
  dark:  Tuile::Theme::DARK.with(custom: { accent: Color::DARK_ORANGE }),
  light: Tuile::Theme::LIGHT.with(custom: { accent: Color::DARK_ORANGE3 })
)
screen.theme_def = APP_THEME

Both members must declare the same Tuile::Theme#custom key set. Without that, a token present only in one member would raise ‘KeyError` at the unpredictable moment the user flips OS appearance; checking here turns it into an immediate construction-time failure.

Constant Summary collapse

DEFAULT =

The built-in pair: Tuile::Theme::DARK / Tuile::Theme::LIGHT.

Returns:

new(dark: Theme::DARK, light: Theme::LIGHT)

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dark:, light:) ⇒ ThemeDef

Returns a new instance of ThemeDef.

Parameters:

Raises:



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/tuile/theme_def.rb', line 33

def initialize(dark:, light:)
  raise TypeError, "dark must be a Tuile::Theme, got #{dark.inspect}" unless dark.is_a?(Theme)
  raise TypeError, "light must be a Tuile::Theme, got #{light.inspect}" unless light.is_a?(Theme)

  if dark.custom.keys.sort != light.custom.keys.sort
    raise ArgumentError,
          "dark and light must declare the same custom tokens; " \
          "dark has #{dark.custom.keys.sort.inspect}, light has #{light.custom.keys.sort.inspect}"
  end

  super
end

Class Attribute Details

.defaultThemeDef

The definition newly-constructed Screens start from (see Screen#theme_def); initially DEFAULT. Reassigning affects future screens only — an already-constructed screen keeps its definition until Screen#theme_def=.

Intended for test suites: production apps assign Screen#theme_def= once at startup, but component specs build a fresh FakeScreen per example, and a component reading a custom token (‘theme`) would `KeyError` against the built-in default. Point this at the app’s definition once and every Screen.fake carries it:

Tuile::ThemeDef.default = APP_THEME   # spec_helper.rb, once
before { Screen.fake }                # theme[:accent] resolves

Returns:



73
74
75
# File 'lib/tuile/theme_def.rb', line 73

def default
  @default
end

Instance Attribute Details

#darkTheme (readonly)

The theme applied on dark terminal backgrounds.

Returns:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/tuile/theme_def.rb', line 28

class ThemeDef < Data.define(:dark, :light)
  # @param dark [Theme]
  # @param light [Theme]
  # @raise [TypeError] when a member is not a {Theme}.
  # @raise [ArgumentError] when the members' {Theme#custom} key sets differ.
  def initialize(dark:, light:)
    raise TypeError, "dark must be a Tuile::Theme, got #{dark.inspect}" unless dark.is_a?(Theme)
    raise TypeError, "light must be a Tuile::Theme, got #{light.inspect}" unless light.is_a?(Theme)

    if dark.custom.keys.sort != light.custom.keys.sort
      raise ArgumentError,
            "dark and light must declare the same custom tokens; " \
            "dark has #{dark.custom.keys.sort.inspect}, light has #{light.custom.keys.sort.inspect}"
    end

    super
  end

  # The member for the given color scheme. Anything other than `:light`
  # selects {#dark}, matching {TerminalBackground.detect}'s
  # inconclusive-means-dark policy.
  # @param scheme [Symbol] `:dark` or `:light`.
  # @return [Theme]
  def for(scheme) = scheme == :light ? light : dark

  # The built-in pair: {Theme::DARK} / {Theme::LIGHT}.
  # @return [ThemeDef]
  DEFAULT = new(dark: Theme::DARK, light: Theme::LIGHT)

  class << self
    # The definition newly-constructed {Screen}s start from (see
    # {Screen#theme_def}); initially {DEFAULT}. Reassigning affects
    # future screens only — an already-constructed screen keeps its
    # definition until {Screen#theme_def=}.
    #
    # Intended for test suites: production apps assign
    # {Screen#theme_def=} once at startup, but component specs build a
    # fresh {FakeScreen} per example, and a component reading a custom
    # token (`theme[:accent]`) would `KeyError` against the built-in
    # default. Point this at the app's definition once and every
    # {Screen.fake} carries it:
    #
    #   Tuile::ThemeDef.default = APP_THEME   # spec_helper.rb, once
    #   before { Screen.fake }                # theme[:accent] resolves
    # @return [ThemeDef]
    attr_reader :default

    # @param theme_def [ThemeDef]
    # @raise [TypeError] when not a {ThemeDef}.
    def default=(theme_def)
      raise TypeError, "expected ThemeDef, got #{theme_def.inspect}" unless theme_def.is_a?(ThemeDef)

      @default = theme_def
    end
  end
  @default = DEFAULT
end

#lightTheme (readonly)

The theme applied on light terminal backgrounds.

Returns:



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/tuile/theme_def.rb', line 28

class ThemeDef < Data.define(:dark, :light)
  # @param dark [Theme]
  # @param light [Theme]
  # @raise [TypeError] when a member is not a {Theme}.
  # @raise [ArgumentError] when the members' {Theme#custom} key sets differ.
  def initialize(dark:, light:)
    raise TypeError, "dark must be a Tuile::Theme, got #{dark.inspect}" unless dark.is_a?(Theme)
    raise TypeError, "light must be a Tuile::Theme, got #{light.inspect}" unless light.is_a?(Theme)

    if dark.custom.keys.sort != light.custom.keys.sort
      raise ArgumentError,
            "dark and light must declare the same custom tokens; " \
            "dark has #{dark.custom.keys.sort.inspect}, light has #{light.custom.keys.sort.inspect}"
    end

    super
  end

  # The member for the given color scheme. Anything other than `:light`
  # selects {#dark}, matching {TerminalBackground.detect}'s
  # inconclusive-means-dark policy.
  # @param scheme [Symbol] `:dark` or `:light`.
  # @return [Theme]
  def for(scheme) = scheme == :light ? light : dark

  # The built-in pair: {Theme::DARK} / {Theme::LIGHT}.
  # @return [ThemeDef]
  DEFAULT = new(dark: Theme::DARK, light: Theme::LIGHT)

  class << self
    # The definition newly-constructed {Screen}s start from (see
    # {Screen#theme_def}); initially {DEFAULT}. Reassigning affects
    # future screens only — an already-constructed screen keeps its
    # definition until {Screen#theme_def=}.
    #
    # Intended for test suites: production apps assign
    # {Screen#theme_def=} once at startup, but component specs build a
    # fresh {FakeScreen} per example, and a component reading a custom
    # token (`theme[:accent]`) would `KeyError` against the built-in
    # default. Point this at the app's definition once and every
    # {Screen.fake} carries it:
    #
    #   Tuile::ThemeDef.default = APP_THEME   # spec_helper.rb, once
    #   before { Screen.fake }                # theme[:accent] resolves
    # @return [ThemeDef]
    attr_reader :default

    # @param theme_def [ThemeDef]
    # @raise [TypeError] when not a {ThemeDef}.
    def default=(theme_def)
      raise TypeError, "expected ThemeDef, got #{theme_def.inspect}" unless theme_def.is_a?(ThemeDef)

      @default = theme_def
    end
  end
  @default = DEFAULT
end

Instance Method Details

#for(scheme) ⇒ Theme

The member for the given color scheme. Anything other than ‘:light` selects #dark, matching Tuile::TerminalBackground.detect’s inconclusive-means-dark policy.

Parameters:

  • scheme (Symbol)

    ‘:dark` or `:light`.

Returns:



51
# File 'lib/tuile/theme_def.rb', line 51

def for(scheme) = scheme == :light ? light : dark