Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds support for native quoted strings #13

Merged
merged 1 commit into from
Jul 13, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions lib/sassc/functions_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ def setup(native_options)
when :sass_null
# no-op
when :sass_string
native_string = Native.string_get_value(native_value)
argument = Script::String.new(Script::String.unquote(native_string), Script::String.type(native_string))
value = Native.string_get_value(native_value)
type = Native.string_get_type(native_value)
argument = Script::String.new(value, type)

custom_function_arguments << argument
when :sass_color
Expand All @@ -46,11 +47,11 @@ def setup(native_options)
next error_tag if error_tag

begin
value = functions.send(custom_function, *custom_function_arguments)
script_value = functions.send(custom_function, *custom_function_arguments)

if value
value = Script::String.new(Script::String.unquote(value.to_s), value.type)
value.to_native
if script_value
script_value.options = @options
script_value.to_native
else
Script::String.new("").to_native
end
Expand Down
11 changes: 11 additions & 0 deletions lib/sassc/native/native_functions_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@ module Native

# ADDAPI union Sass_Value* ADDCALL sass_make_number (double val, const char* unit);
attach_function :sass_make_number, [:double, :string], :sass_value_ptr

# ADDAPI union Sass_Value* ADDCALL sass_make_string (const char* val);
attach_function :sass_make_string, [:string], :sass_value_ptr

# ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val);
attach_function :sass_make_qstring, [:string], :sass_value_ptr

# ADDAPI enum Sass_Tag ADDCALL sass_value_get_tag (const union Sass_Value* v);
attach_function :sass_value_get_tag, [:sass_value_ptr], SassTag
Expand All @@ -24,6 +28,13 @@ module Native
# ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
attach_function :sass_string_get_value, [:sass_value_ptr], :string

# ADDAPI bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
attach_function :sass_string_is_quoted, [:sass_value_ptr], :bool

def self.string_get_type(native_value)
string_is_quoted(native_value) ? :string : :identifier
end

# ADDAPI double ADDCALL sass_color_get_r (const union Sass_Value* v);
# ADDAPI void ADDCALL sass_color_set_r (union Sass_Value* v, double r);
# ADDAPI double ADDCALL sass_color_get_g (const union Sass_Value* v);
Expand Down
2 changes: 1 addition & 1 deletion lib/sassc/script.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ def self.formatted_function_name(function_name)
end

require_relative "script/functions"
require_relative "script/string"

module Sass
module Script
Expand All @@ -26,4 +25,5 @@ module Script

require 'sass/util'
require 'sass/script/value/base'
require_relative "script/string"
require_relative "script/color"
102 changes: 7 additions & 95 deletions lib/sassc/script/string.rb
Original file line number Diff line number Diff line change
@@ -1,102 +1,14 @@
require 'sass/script/value/string'

module SassC
module Script
class String
# The Ruby value of the string.
#
# @return [String]
attr_reader :value

# Whether this is a CSS string or a CSS identifier.
# The difference is that strings are written with double-quotes,
# while identifiers aren't.
#
# @return [Symbol] `:string` or `:identifier`
attr_reader :type

def self.value(contents)
contents.gsub("\\\n", "").gsub(/\\(?:([0-9a-fA-F]{1,6})\s?|(.))/) do
next $2 if $2
# Handle unicode escapes as per CSS Syntax Level 3 section 4.3.8.
code_point = $1.to_i(16)
if code_point == 0 || code_point > 0x10FFFF ||
(code_point >= 0xD800 && code_point <= 0xDFFF)
'�'
else
[code_point].pack("U")
end
end
end

def self.quote(contents, quote = nil)
# Short-circuit if there are no characters that need quoting.
unless contents =~ /[\n\\"']/
quote ||= '"'
return "#{quote}#{contents}#{quote}"
end

if quote.nil?
if contents.include?('"')
if contents.include?("'")
quote = '"'
else
quote = "'"
end
else
quote = '"'
end
end

# Replace single backslashes with multiples.
contents = contents.gsub("\\", "\\\\\\\\")

if quote == '"'
contents = contents.gsub('"', "\\\"")
class String < ::Sass::Script::Value::String
def to_native(opts = {})
if opts[:quote] == :none || type == :identifier
Native::make_string(to_s)
else
contents = contents.gsub("'", "\\'")
Native::make_qstring(to_s)
end

contents = contents.gsub(/\n(?![a-fA-F0-9\s])/, "\\a").gsub("\n", "\\a ")
"#{quote}#{contents}#{quote}"
end

def self.type(contents)
unquote(contents) == contents ? :identifier : :string
end

def self.unquote(contents)
s = contents.dup

case contents[0, 1]
when "'", '"', '`'
s[0] = ''
end

case contents[-1, 1]
when "'", '"', '`'
s[-1] = ''
end

return s
end

# Creates a new string.
#
# @param value [String] See \{#value}
# @param type [Symbol] See \{#type}
def initialize(value, type = :identifier)
value.freeze unless value.nil? || value == true || value == false
@value = value
@type = type
end

def to_native
Native::make_string(to_s)
end

# @see Value#to_s
def to_s(opts = {})
return @value.gsub(/\n\s*/, ' ') if opts[:quote] == :none || @type == :identifier
SassC::Script::String.quote(value, opts[:quote])
end
end
end
Expand Down
30 changes: 16 additions & 14 deletions test/functions_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ def teardown
end

def test_functions_may_return_sass_string_type
engine = Engine.new("div {url: url(sass_return_path('foo.svg'));}")
engine = Engine.new(<<-SCSS)
div {
url: url(sass_return_path("foo.svg")); }
SCSS

assert_equal <<-EOS, engine.render
assert_equal <<-EXPECTED_SCSS, engine.render
div {
url: url("foo.svg"); }
EOS
EXPECTED_SCSS
end

def test_functions_work_with_varying_quotes_and_string_types
Expand Down Expand Up @@ -54,12 +57,17 @@ def test_function_with_no_return_value
end

def test_function_with_optional_arguments
engine = Engine.new("div {url: optional_arguments('first'); url: optional_arguments('second', 'qux')}")
assert_equal <<-EOS, engine.render
engine = Engine.new(<<-SCSS)
div {
url: optional_arguments('first');
url: optional_arguments('second', 'qux'); }
SCSS

assert_equal <<-EXPECTED_SCSS, engine.render
div {
url: "first/bar";
url: "second/qux"; }
EOS
EXPECTED_SCSS
end

def test_functions_may_accept_sass_color_type
Expand Down Expand Up @@ -103,12 +111,6 @@ def test_function_with_error

private

SassString = Struct.new(:value, :type) do
def to_s
value
end
end

module Script::Functions
def javascript_path(path)
Script::String.new("/js/#{path.value}", :string)
Expand All @@ -119,11 +121,11 @@ def no_return_path(path)
end

def sass_return_path(path)
return SassString.new("'#{path.value}'", :string)
Script::String.new("#{path.value}", :string)
end

def optional_arguments(path, optional = "bar")
return SassString.new("#{path}/#{optional}", :string)
Script::String.new("#{path.value}/#{optional}", :string)
end

def function_that_raises_errors()
Expand Down