Class: Esvg::SVG

Inherits:
Object
  • Object
show all
Defined in:
lib/esvg/svg.rb

Constant Summary collapse

CONFIG =
{
  path: Dir.pwd,
  base_class: 'svg-icon',
  namespace: 'icon',
  namespace_after: true,
  font_size: '1em',
  stylesheet_embed: false,
  output_path: Dir.pwd
}
CONFIG_RAILS =
{
  path: "app/assets/svg_icons",
  css_path: "app/assets/stylesheets/_svg_icons.scss",
  html_path: "app/views/shared/_svg_icons.html"
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ SVG

Returns a new instance of SVG.



21
22
23
24
# File 'lib/esvg/svg.rb', line 21

def initialize(options={})
  config(options)
  read_icons
end

Instance Attribute Details

#filesObject

Returns the value of attribute files.



3
4
5
# File 'lib/esvg/svg.rb', line 3

def files
  @files
end

Instance Method Details

#config(options = {}) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/esvg/svg.rb', line 136

def config(options={})
  @config ||= begin
    paths = [options[:config_file], 'config/esvg.yml', 'esvg.yml'].compact

    config = if path = paths.select{ |p| File.exist?(p)}.first
      CONFIG.merge(symbolize_keys(YAML.load(File.read(path) || {}))).merge(options)
    else
      CONFIG.merge(options)
    end

    config.merge!(CONFIG_RAILS) if Esvg.rails?
    config.merge(options)

    config[:css_path]  ||= File.join(config[:output_path], 'esvg.scss')
    config[:html_path] ||= File.join(config[:output_path], 'esvg.html')
    config.delete(:output_path)

    config
  end
end

#dasherize(input) ⇒ Object



184
185
186
# File 'lib/esvg/svg.rb', line 184

def dasherize(input)
  input.gsub(/\W/, '-').gsub(/-{2,}/, '-')
end

#desc(options) ⇒ Object



130
131
132
133
134
# File 'lib/esvg/svg.rb', line 130

def desc(options)
  if options[:desc]
    "<desc>#{options[:desc]}</desc>"
  end
end

#dimensions(input) ⇒ Object



163
164
165
166
167
168
169
# File 'lib/esvg/svg.rb', line 163

def dimensions(input)
  dimensions = [] 
  %w(viewBox height width).map do |dimension|
      dimensions << input.scan(/<svg.+(#{dimension}=["'].+?["'])/).flatten.first
  end
  dimensions.compact.join(' ')
end

#find_filesObject



188
189
190
191
192
# File 'lib/esvg/svg.rb', line 188

def find_files
  path = File.join(config[:path], '*.svg')

  Dir[path].uniq.sort_by{ |f| File.mtime(f) }
end

#html(names = []) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/esvg/svg.rb', line 94

def html(names=[])
  names = Array(names) # In case a single string is passed

  if @files.empty?
    ''
  else
    files.each do |name, contents|
      @svgs[name] = contents.gsub(/<svg.+?>/, %Q{<symbol id="#{icon_name(name)}" #{dimensions(contents)}>})  # convert svg to symbols
                     .gsub(/<\/svg/, '</symbol')     # convert svg to symbols
                     .gsub(/style=['"].+?['"]/, '')  # remove inline styles
                     .gsub(/\n/, '')                 # remove endlines
                     .gsub(/\s{2,}/, ' ')            # remove whitespace
                     .gsub(/>\s+</, '><')            # remove whitespace between tags
    end

    if names.empty?
      icons = @svgs
    else
      icons = @svgs.select { |k,v| names.include?(k) }
    end

    %Q{<svg class="icon-symbols" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="display:none">#{icons.values.join("\n")}</svg>}
  end
end

#icon_name(name) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/esvg/svg.rb', line 171

def icon_name(name)
  if @files[name].nil?
    raise "No icon named #{name} exists at #{config[:path]}"
  end

  name = dasherize(name)
  if config[:namespace_after]
    "#{name}-#{config[:namespace]}"
  else
    "#{config[:namespace]}-#{name}"
  end
end

#modified?Boolean

Returns:

  • (Boolean)


26
27
28
29
# File 'lib/esvg/svg.rb', line 26

def modified?
  mtime = File.mtime(find_files.last)
  @mtime != mtime
end

#read_iconsObject



31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/esvg/svg.rb', line 31

def read_icons
  @files = {}
  @mtime = {}
  @svgs  = {}

  found = find_files
  @mtime = File.mtime(found.last)

  found.each do |f|
    svg = File.read(f)
    @files[File.basename(f, ".*")] = SvgOptimizer.optimize(svg)
  end
end

#stylesheetObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/esvg/svg.rb', line 65

def stylesheet
  styles = []
  preamble = %Q{%svg-icon { 
clip: auto;
font-size: #{config[:font_size]};
background: {
  size: auto 1em;
  repeat: no-repeat;
  position: center center;
}
display: inline-block;
overflow: hidden;
height: 1em;
width: 1em;
color: transparent;
vertical-align: middle;
  }}
  styles << preamble

  files.each do |name, contents|
    f = contents.gsub(/</, '%3C') # escape <
                .gsub(/>/, '%3E') # escape >
                .gsub(/#/, '%23') # escape #
                .gsub(/\n/,'')    # remove newlines
    styles << ".#{icon_name(name)} { background-image: url('data:image/svg+xml;utf-8,#{f}'); @extend %svg-icon; }"
  end
  styles.join("\n")
end

#svg_icon(file, options = {}) ⇒ Object



119
120
121
122
# File 'lib/esvg/svg.rb', line 119

def svg_icon(file, options={})
  name = icon_name(file)
  %Q{<svg class="#{config[:base_class]} #{name} #{options[:class] || ""}" #{dimensions(@files[file])}><use xlink:href="##{name}"/>#{title(options)}#{desc(options)}</svg>}.html_safe
end

#symbolize_keys(hash) ⇒ Object



157
158
159
160
161
# File 'lib/esvg/svg.rb', line 157

def symbolize_keys(hash)
  h = {}
  hash.each {|k,v| h[k.to_sym] = v }
  h
end

#title(options) ⇒ Object



124
125
126
127
128
# File 'lib/esvg/svg.rb', line 124

def title(options)
  if options[:title]
    "<title>#{options[:title]}</title>"
  end
end

#write_htmlObject



55
56
57
58
59
60
61
62
63
# File 'lib/esvg/svg.rb', line 55

def write_html
  unless @files.empty?
    FileUtils.mkdir_p(File.expand_path(File.dirname(config[:html_path])))

    File.open(config[:html_path], 'w') do |io|
      io.write(html)
    end
  end
end

#write_stylesheetObject



45
46
47
48
49
50
51
52
53
# File 'lib/esvg/svg.rb', line 45

def write_stylesheet
  unless @files.empty?
    FileUtils.mkdir_p(File.expand_path(File.dirname(config[:css_path])))

    File.open(config[:css_path], 'w') do |io|
      io.write(stylesheet)
    end
  end
end