module Sass::Script::Functions
env
require 'tinypng'
strftime
inline_image
取图片base64编码
url重写
Constants
- FONT_TYPES
- MIME_TYPES
- PATH_REGEX
Public Instance Methods
Returns the config associated with the given name. Configs are be grouped by ‘SASS_ENV` environment.
Examples: $app-config: (
development: ( foo: bar ), production: ( foo: baz )
);
$ sass –watch -r base.sass src:dist app-config(foo) => bar
$ SASS_ENV=production sass –watch -r base.sass src:dist app-config(foo) => baz
# File lib/sassmagic/utils.rb, line 40 def app_config(name) assert_type name, :String # debugger config = environment.global_env.var('app-config') return null unless config.is_a? Sass::Script::Value::Map config = map_get(config, env(identifier('sass-env'))) map_get(config, name) end
Dynamically calls a function. This can call user-defined functions, built-in functions, or plain CSS functions. It will pass along all arguments, including keyword arguments, to the called function.
@example
call(rgb, 10, 100, 255) => #0a64ff call(scale-color, #0a64ff, $lightness: -10%) => #0058ef $fn: nth; call($fn, (a b c), 2) => b
@overload call($name, $args…)
@param $name [String] The name of the function to call.
# File lib/sassmagic/reset.rb, line 48 def call(name, *args) assert_type name, :String, :name kwargs = args.last.is_a?(Hash) ? args.pop : {} funcall = Sass::Script::Tree::Funcall.new( name.value, args.map {|a| Sass::Script::Tree::Literal.new(a)}, Sass::Util.map_vals(kwargs) {|v| Sass::Script::Tree::Literal.new(v)}, nil, nil) funcall.options = options perform(funcall) end
Returns the value of environment variable associated with the given name. Returns null if the named variable does not exist.
Examples: env(SASS_ENV) => development env(sass_env) => development env(sass-env) => development
# File lib/sassmagic/utils.rb, line 17 def env(name) assert_type name, :String ruby_to_sass(ENV[name.value.gsub('-', '_').upcase]) end
# File lib/sassmagic/utils.rb, line 142 def inline_image(path, mime_type = nil) # debugger path = path.value real_path = File.expand_path("#{File.dirname(options[:filename])}/#{path}") inline_image_string(data(real_path), compute_mime_type(path, mime_type)) end
protected
# File lib/sassmagic/utils.rb, line 483 def load_json(path) if File::exists?( path ) JSON.load( read_file(File.expand_path(path)).to_s.gsub(/(\\r|\\n)/, '') ) end end
Parses a local json file, returns a map, and the result will be cached. If the ‘path` is not a absolute path, relative to current process directory.
Examples: parse-json(‘~/Desktop/example.json’) parse-json(‘package.json’)
# File lib/sassmagic/utils.rb, line 468 def parse_json(path) assert_type path, :String path = File.expand_path(path.value) if $cached_files.key? path Sass.logger.debug "Reading file from cache: #{path}" $cached_files[path] else $cached_files[path] = ruby_to_sass(load_json(path)) end end
# File lib/sassmagic/reset.rb, line 29 def pxtorem(string) assert_type string, :String Sass::Script::Value::String.new(string+'rem') end
# File lib/sassmagic/utils.rb, line 491 def read_file(path) raise Sass::SyntaxError, "File not found or cannot be read: #{path}" unless File.readable? path Sass.logger.debug "Reading file: #{path}" File.open(path, 'rb') { |f| f.read } end
# File lib/sassmagic/reset.rb, line 24 def reverse(string) assert_type string, :String Sass::Script::Value::String.new(string.value.reverse) end
Formats time according to the directives in the given format string. Read more: www.ruby-doc.org/core-2.1.1/Time.html#method-i-strftime
Examples: strftime() => 1399392214 strftime(‘%FT%T%:z’) => 2014-05-07T00:03:34+08:00 strftime(‘at %I:%M%p’) => at 12:03AM
# File lib/sassmagic/utils.rb, line 63 def strftime(format = nil) time = Time.now.localtime if format assert_type format, :String identifier(time.strftime(format.value)) else identifier(time.to_i.to_s) end end
Reinforce the official ‘url()` in CSS to support multi url and data url. Activates only when all paths are wrapped with quotes.
Examples: url() => url(
) # Did nothing url(‘
’) => url(a.com/b.png?1399394203) url(‘a.png’, ‘b.png’) => url(a.png?1399394203), url(b.png?1399394203) url(‘a.eot#iefix’, ‘b.woff’) => url(a.eot?1399394203#iefix) format(‘embedded-opentype’), url(b.woff?1399394203) format(‘woff’)
url(‘a.png’, $timestamp: false) => url(a.png) url(‘a.png’, $timestamp: ‘1.0.0’) => url(a.png?1.0.0)
$app-config: (timestamp: ‘1.0.0’); url(‘a.png’) => url(a.png?1.0.0)
$app-config: (timestamp: ‘p1’); url(‘a.png’, $timestamp: ‘p0’) => url(a.png?p0)
url(‘a.png’, $base64: true) => url(data:image/png;base64,iVBORw…)
# File lib/sassmagic/utils.rb, line 243 def url(*paths) # debugger $configHash ||= load_json(File.expand_path("#{File.dirname(options[:filename])}/../config/sassmagic.json")) || Hash.new kwargs = paths.last.is_a?(Hash) ? paths.pop : {} raise Sass::SyntaxError, 'url() needs one path at least' if paths.empty? encode = kwargs['base64'] == bool(true) ts = timestamp(kwargs['timestamp']) paths = paths.map { |path| sass_to_ruby(path) }.flatten .map { |path| compress_img(path, encode, ts); } list(paths, :comma) end
Protected Instance Methods
# File lib/sassmagic/utils.rb, line 152 def inline_image_string(data, mime_type) data = [data].flatten.pack('m').gsub("\n","") url = "url(data:#{mime_type};base64,#{data})" unquoted_string(url) end
# File lib/sassmagic/utils.rb, line 108 def ruby_to_sass(obj) return bool(obj) if obj.is_a?(TrueClass) || obj.is_a?(FalseClass) return null if obj.nil? return number(obj) if obj.is_a? Numeric return to_sass_list(obj) if obj.is_a? Array return to_sass_map(obj) if obj.is_a? Hash identifier(obj.to_s) end
# File lib/sassmagic/utils.rb, line 81 def sass_to_ruby(obj) return to_ruby_hash(obj) if obj.is_a? Sass::Script::Value::Map return to_ruby_array(obj) if obj.is_a? Sass::Script::Value::List return obj.inspect if obj.is_a? Sass::Script::Value::Color obj.value end
# File lib/sassmagic/utils.rb, line 95 def to_ruby_array(sass_list) sass_list.to_a.map do |item| sass_to_ruby(item) end end
# File lib/sassmagic/utils.rb, line 88 def to_ruby_hash(sass_map) sass_map.to_h.inject({}) do |memo, (k, v)| memo[k.to_s] = sass_to_ruby(v) memo end end
# File lib/sassmagic/utils.rb, line 130 def to_sass_list(ruby_array) list(ruby_array.map { |item| ruby_to_sass(item) }, :comma) end
# File lib/sassmagic/utils.rb, line 117 def to_sass_map(ruby_hash) sass_map = map({}) ruby_hash.each do |k, v| sass_map = map_merge( sass_map, map(Hash[identifier(k.to_s), ruby_to_sass(v)]) ) end sass_map end
Private Instance Methods
# File lib/sassmagic/utils.rb, line 407 def change_path(path) # debugger $configHash["imagesPath"] ||= Hash.new if $configHash["imagesPath"].has_key?(File.expand_path("#{File.dirname(options[:filename])}/#{path}")) return $configHash["imagesPath"][File.expand_path("#{File.dirname(options[:filename])}/#{path}")] end # 调用上传任务 # debugger if (!$configHash.has_key?'imageLoader') || ($configHash["imageLoader"] == '') return path end nodetask = $configHash["imageLoader"] || false taskargs = File.expand_path("#{File.dirname(options[:filename])}/#{path}") # debugger if nodetask && File::exists?( File.expand_path("#{File.dirname(options[:filename])}/#{nodetask}") ) task = system('node '+File.expand_path("#{File.dirname(options[:filename])}/#{nodetask}")+' '+File.expand_path("#{File.dirname(options[:filename])}/../config/sassmagic.json")+' '+taskargs) if task # puts 'nodetask success' $configHash = load_json(File.expand_path("#{File.dirname(options[:filename])}/../config/sassmagic.json")) $configHash["imagesPath"] ||= Hash.new if $configHash["imagesPath"].has_key?(taskargs) return $configHash["imagesPath"][taskargs] else return path end else # puts 'nodetask faile' if $configHash["imagesPath"].has_key?(taskargs) return $configHash["imagesPath"][taskargs] else return path end end else if $configHash["imagesPath"].has_key?(taskargs) return $configHash["imagesPath"][taskargs] else return path end end end
# File lib/sassmagic/utils.rb, line 261 def compress_img(path,encode,ts) # debugger if path.is_a?(String) && path =~ PATH_REGEX path, ext, query, anchor = $1 + $2, $2[1..-1].downcase.to_sym, $3, $4 if MIME_TYPES.key? ext #图片压缩 # debugger # 未设置tinypngKye或者url图片,则不优化 if !$configHash.has_key?('tinypngKye') || $configHash['tinypngKye'] == '' || path =~ /^(http:|https:)\/\// else output = path.dup.gsub(/\.(png|jpg)$/,'_tinypng.\1') if File.exist?("#{File.dirname(options[:filename])}/#{output}") # debug exception while processing events: can't modify frozen String , Backtrace: path.gsub!(/\.(png|jpg)$/,'_tinypng.\1') else require "net/https" require "uri" key = $configHash['tinypngKye'] || '' input = path # real_path = File.expand_path("#{File.dirname(path)}/#{path}") # output = "tiny-output.png" uri = URI.parse("https://api.tinypng.com/shrink") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true # Uncomment below if you have trouble validating our SSL certificate. # Download cacert.pem from: http://curl.haxx.se/ca/cacert.pem # http.ca_file = File.join(File.dirname(__FILE__), "cacert.pem") request = Net::HTTP::Post.new(uri.request_uri) request.basic_auth("api", key) response = http.request(request, File.binread("#{File.dirname(options[:filename])}/#{input}")) # debugger if response.code == "201" # Compression was successful, retrieve output from Location header. # debugger output = path path.gsub!(/\.(png|jpg)$/,'_tinypng.\1') # output['.png'] = '_tinypng.png' # output['.jpg'] = '_tinypng.jpg' File.binwrite("#{File.dirname(options[:filename])}/#{output}", http.get(response["location"]).body) else # Something went wrong! You can parse the JSON body for details. puts "Compression failed" end end end end end #调用to_url函数 to_url(path, encode, ts) end
# File lib/sassmagic/utils.rb, line 159 def compute_mime_type(path, mime_type = nil) return mime_type.value if mime_type case path when /\.png$/i 'image/png' when /\.jpe?g$/i 'image/jpeg' when /\.gif$/i 'image/gif' when /\.svg$/i 'image/svg+xml' when /\.otf$/i 'font/opentype' when /\.eot$/i 'application/vnd.ms-fontobject' when /\.ttf$/i 'font/truetype' when /\.woff$/i 'application/font-woff' when /\.off$/i 'font/openfont' when /\.([a-zA-Z]+)$/ "image/#{Regexp.last_match(1).downcase}" else raise Sass.logger.debug("A mime type could not be determined for #{path}, please specify one explicitly.") end end
# File lib/sassmagic/utils.rb, line 187 def data(real_path) # debugger if File.readable?(real_path) File.open(real_path, "rb") {|io| io.read} else raise Sass.logger.debug("File not found or cannot be read: #{real_path}") end end
# File lib/sassmagic/utils.rb, line 394 def output_data(path, ext) data = [read_file(File.expand_path(File.expand_path("#{File.dirname(options[:filename])}/#{path}")))].pack('m').gsub(/\s/, '') "url(data:#{MIME_TYPES[ext]};base64,#{data})" end
# File lib/sassmagic/utils.rb, line 399 def output_path(path, ext, query, anchor, ts) query += sign(query) + ts unless ts.nil? output = "url(#{path}#{query}#{anchor})" return output unless FONT_TYPES.key? ext [identifier(output), identifier("format('#{FONT_TYPES[ext]}')")] end
# File lib/sassmagic/utils.rb, line 333 def sign(query) case query.size when 0 '?' when 1 '' else '&' end end
# File lib/sassmagic/utils.rb, line 321 def timestamp(ts) # no kwargs if ts.nil? cfg = app_config(identifier('timestamp')) ts = cfg == null ? bool(true) : cfg end return nil unless ts.to_bool return strftime.value if ts.is_a? Sass::Script::Value::Bool ts.value.to_s end
# File lib/sassmagic/utils.rb, line 344 def to_url(path, encode, ts) output = "url(#{path})" # debugger if path.is_a?(String) && path =~ PATH_REGEX path, ext, query, anchor = $1 + $2, $2[1..-1].downcase.to_sym, $3, $4 if MIME_TYPES.key? ext # 网络地址 if path =~ /^(http:|https:)\/\// # path = path.replace(/(http:\/\/)|(http:\/\/)/,'//') path['http://'] = '//' output = output_path(path, ext, query, anchor, ts) else if $configHash["imageMaxSize"] #替换图片地址 output = if encode output_data(path, ext) else #替换图片 # debugger filesize = File.size(File.expand_path("#{File.dirname(options[:filename])}/#{path}")) if filesize < $configHash["imageMaxSize"].to_i output_data(path, ext) else path = change_path(path) output_path(path, ext, query, anchor, ts) end end else output = if encode output_data(path, ext) else output_path(path, ext, query, anchor, ts) end end end end end if output.is_a? Array list(output, :space) else identifier(output) end end