require 'yaml'
require 'json'
module Esvg
class SVG
attr_accessor :files, :svgs
CONFIG = {
path: Dir.pwd,
base_class: 'svg-icon',
namespace: 'icon',
optimize: false,
npm_path: false,
namespace_before: true,
font_size: '1em',
output_path: Dir.pwd,
verbose: false,
format: 'js',
alias: {}
}
CONFIG_RAILS = {
path: "app/assets/esvg"
}
def initialize(options={})
config(options)
@svgo = nil
@svgs = {}
read_files
end
def config(options={})
@config ||= begin
paths = [options[:config_file], 'config/esvg.yml', 'esvg.yml'].compact
config = CONFIG
config.merge!(CONFIG_RAILS) if Esvg.rails?
if path = paths.select{ |p| File.exist?(p)}.first
config.merge!(symbolize_keys(YAML.load(File.read(path) || {})))
end
config.merge!(options)
if config[:cli]
config[:path] = File.expand_path(config[:path])
config[:output_path] = File.expand_path(config[:output_path])
end
config[:js_path] ||= File.join(config[:output_path], 'esvg.js')
config[:css_path] ||= File.join(config[:output_path], 'esvg.css')
config[:html_path] ||= File.join(config[:output_path], 'esvg.html')
config.delete(:output_path)
config[:aliases] = load_aliases(config[:alias])
config
end
end
# Load aliases from configuration.
# returns a hash of aliasees mapped to a name.
# Converts configuration YAML:
# alias:
# foo: bar
# baz: zip, zop
# To output:
# { :bar => "foo", :zip => "baz", :zop => "baz" }
#
def load_aliases(aliases)
a = {}
aliases.each do |name,alternates|
alternates.split(',').each do |val|
a[dasherize(val.strip).to_sym] = dasherize(name.to_s)
end
end
a
end
def get_alias(name)
config[:aliases][dasherize(name).to_sym] || name
end
def embed
return if files.empty?
case config[:format]
when "html"
html
when "js"
js
when "css"
css
end
end
def read_files
@files = {}
# Get a list of svg files and modification times
#
find_files.each do |f|
files[f] = File.mtime(f)
end
puts "Read #{files.size} files from #{config[:path]}" if config[:cli]
process_files
if files.empty? && config[:cli]
puts "No svgs found at #{config[:path]}"
end
end
# Add new svgs, update modified svgs, remove deleted svgs
#
def process_files
files.each do |file, mtime|
name = file_key(file)
if svgs[name].nil? || svgs[name][:last_modified] != mtime
svgs[name] = process_file(file, mtime, name)
end
end
# Remove deleted svgs
#
(svgs.keys - files.keys.map {|file| file_key(file) }).each do |file|
svgs.delete(file)
end
end
def process_file(file, mtime, name)
content = File.read(file).gsub(/.+\?>/,'').gsub(//,'')
{
content: content,
use: use_svg(name, content),
last_modified: mtime
}
end
def use_svg(file, content)
name = classname(get_alias(file))
%Q{}
end
def svg_icon(file, options={})
if !exist?(file)
if fallback = options.delete(:fallback)
svg_icon(fallback, options)
else
raise "no svg named '#{get_alias(file)}' exists at #{config[:path]}"
end
else
embed = use_icon(file)
embed = embed.sub(/class="(.+?)"/, 'class="\1 '+options[:class]+'"') if options[:class]
if options[:style]
if embed.match(/style/)
embed = embed.sub(/style="(.+?)"/, 'style="\1; '+options[:style]+'"')
else
embed = embed.sub(/>