Class: Mutter::Mutterer

Inherits:
Object show all
Defined in:
lib/mutter/mutterer.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(obj = {}) ⇒ Mutterer

Initialize the styles, and load the defaults from styles.yml

@active: currently active styles, which apply to the whole string @styles: contains all the user + default styles



10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/mutter/mutterer.rb', line 10

def initialize obj = {}
  self.reset
  @defaults = load File.dirname(__FILE__) + "/styles"

  case obj
    when Hash       # A style definition: expand quick-styles and merge with @styles
      @styles = obj.inject({}) do |h, (k, v)|
        h.merge k =>
          (v.is_a?(Hash) ? v : { :match => v, :style => [k].flatten })
      end
    when Array      # An array of styles to be activated
      @active = obj
    when Symbol     # A single style to be activated
      self << obj
    when String     # The path of a yaml style-sheet
      @styles = load obj
    else raise ArgumentError
  end

  #
  # Create an instance method for each style
  #
  self.styles.keys.each do |style|
    (class << self; self end).class_eval do
      define_method style do |msg|
        say msg, style
      end
    end if style.is_a? Symbol
  end
end

Class Method Details

.streamObject

Output stream (defaults to STDOUT)

mostly for test purposes


184
185
186
# File 'lib/mutter/mutterer.rb', line 184

def self.stream
  @stream
end

.stream=(io) ⇒ Object



188
189
190
# File 'lib/mutter/mutterer.rb', line 188

def self.stream= io
  @stream = io
end

Instance Method Details

#+(style) ⇒ Object



122
123
124
# File 'lib/mutter/mutterer.rb', line 122

def + style
  dup.tap {|m| m << style }
end

#-(style) ⇒ Object



126
127
128
# File 'lib/mutter/mutterer.rb', line 126

def - style
  dup.tap {|m| m >> style }
end

#<<(style) ⇒ Object

Add and remove styles from the active styles



114
115
116
# File 'lib/mutter/mutterer.rb', line 114

def << style
  @active << style
end

#>>(style) ⇒ Object



118
119
120
# File 'lib/mutter/mutterer.rb', line 118

def >> style
  @active.delete style
end

#clear(opt = :all) ⇒ Object Also known as: reset



45
46
47
48
49
50
51
52
53
54
55
# File 'lib/mutter/mutterer.rb', line 45

def clear opt = :all
  case opt
    when :user    then @styles = {}
    when :default then @defaults = {}
    when :styles  then @styles, @defaults = {}, {}
    when :active  then @active = []
    when :all     then @active, @styles, @defaults = [], {}, {}
    else          raise ArgumentError, "[:user, :default, :active, :all] only"
  end
  self
end

#esc(str, open, close) ⇒ Object

Escape a string, for later replacement



176
177
178
# File 'lib/mutter/mutterer.rb', line 176

def esc str, open, close
  "\e#{open}\e" + str + "\e#{close}\e"
end

#load(styles) ⇒ Object

Loads styles from a YAML style-sheet,

and converts the keys to symbols


62
63
64
65
66
67
68
# File 'lib/mutter/mutterer.rb', line 62

def load styles
  styles += '.yml' unless styles =~ /\.ya?ml/
  YAML.load_file(styles).inject({}) do |h, (key, value)|
    value = { :match => value['match'], :style => value['style'] }
    h.merge key.to_sym => value
  end
end

#parse(string) ⇒ Object

Parse a string to ANSI codes

if the glyph is a pair, we match [0] as the start
and [1] as the end marker.
the matches are sent to +stylize+


137
138
139
140
141
142
143
144
145
146
147
# File 'lib/mutter/mutterer.rb', line 137

def parse string
  self.styles.inject(string) do |str, (name, options)|
    glyph, style = options[:match], options[:style]
    if glyph.is_a? Array
      str.gsub(/#{Regexp.escape(glyph.first)}(.*?)
                #{Regexp.escape(glyph.last)}/x) { stylize $1, style }
    else
      str.gsub(/(#{Regexp.escape(glyph)}+)(.*?)\1/) { stylize $2, style }
    end
  end
end

#process(msg, *styles) ⇒ Object Also known as: []

Parse the message, but also apply a style on the whole thing



83
84
85
# File 'lib/mutter/mutterer.rb', line 83

def process msg, *styles
  stylize(parse(msg), @active + styles).gsub(/\e(\d+)\e/, "\e[\\1m")
end

#say(msg, *styles) ⇒ Object Also known as: print

Output to @stream



73
74
75
76
# File 'lib/mutter/mutterer.rb', line 73

def say msg, *styles
  self.write (ENV['TERM'].include?('color') ? process(msg, *styles) : msg) + "\n"
  return nil
end

#stylesObject



41
42
43
# File 'lib/mutter/mutterer.rb', line 41

def styles
  @defaults.merge @styles
end

#stylize(string, styles = []) ⇒ Object

Apply styles to a string

if the style is a default ANSI style, we add the start
and end sequence to the string.

if the style is a custom style, we recurse, sending
the list of ANSI styles contained in the custom style.

TODO: use ';' delimited codes instead of multiple \e sequences


160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/mutter/mutterer.rb', line 160

def stylize string, styles = []
  [styles].flatten.inject(string) do |str, style|
    style = style.to_sym
    if ANSI[:transforms].include? style
      esc str, *ANSI[:transforms][style]
    elsif ANSI[:colors].include? style
      esc str, ANSI[:colors][style], ANSI[:colors][:reset]
    else
      stylize(str, @styles[style][:style])
    end
  end
end

#watchObject Also known as: oo

Utility function, to make a block interruptible



101
102
103
104
105
106
107
108
# File 'lib/mutter/mutterer.rb', line 101

def watch
  begin
    yield
  rescue Interrupt
    puts
    exit 0
  end
end

#write(str) ⇒ Object

Write to the out stream, and flush it



91
92
93
94
95
96
# File 'lib/mutter/mutterer.rb', line 91

def write str
  self.class.stream.tap do |stream|
    stream.write str
    stream.flush
  end; nil
end