Skip to content
This repository has been archived by the owner on Jun 26, 2018. It is now read-only.

Commit

Permalink
merge
Browse files Browse the repository at this point in the history
  • Loading branch information
Hampton Catlin committed Sep 22, 2014
2 parents b36437f + 14344af commit ddb57b7
Show file tree
Hide file tree
Showing 15 changed files with 719 additions and 59 deletions.
2 changes: 1 addition & 1 deletion Gemfile
@@ -1,4 +1,4 @@
ruby '1.9.3'
#ruby '1.9.3'

source 'https://rubygems.org'

Expand Down
53 changes: 28 additions & 25 deletions Gemfile.lock
Expand Up @@ -8,39 +8,42 @@ PATH
GEM
remote: https://rubygems.org/
specs:
coderay (1.0.9)
ffi (1.0.11)
formatador (0.2.4)
guard (1.7.0)
celluloid (0.16.0)
timers (~> 4.0.0)
coderay (1.1.0)
ffi (1.9.3)
formatador (0.2.5)
guard (2.6.1)
formatador (>= 0.2.4)
listen (>= 0.6.0)
lumberjack (>= 1.0.2)
pry (>= 0.9.10)
thor (>= 0.14.6)
guard-test (0.8.0)
guard (>= 1.1)
listen (~> 2.7)
lumberjack (~> 1.0)
pry (>= 0.9.12)
thor (>= 0.18.1)
guard-test (2.0.5)
guard (~> 2.0)
test-unit (~> 2.2)
listen (1.0.2)
hitimes (1.2.2)
listen (2.7.9)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
rb-inotify (>= 0.9)
rb-kqueue (>= 0.2)
lumberjack (1.0.3)
method_source (0.8.1)
pry (0.9.12)
coderay (~> 1.0.5)
method_source (~> 0.8)
lumberjack (1.0.9)
method_source (0.8.2)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
rake (10.1.0)
rake-compiler (0.8.3)
rake (10.3.2)
rake-compiler (0.9.3)
rake
rb-fsevent (0.9.3)
rb-inotify (0.9.0)
rb-fsevent (0.9.4)
rb-inotify (0.9.5)
ffi (>= 0.5.0)
rb-kqueue (0.2.0)
ffi (>= 0.5.0)
slop (3.4.4)
slop (3.6.0)
test-unit (2.5.5)
thor (0.18.1)
thor (0.19.1)
timers (4.0.1)
hitimes

PLATFORMS
ruby
Expand Down
2 changes: 1 addition & 1 deletion ext/libsass
2 changes: 1 addition & 1 deletion lib/sassc.rb
Expand Up @@ -2,4 +2,4 @@ module SassC
VERSION = "0.0.1"
end

require_relative 'sassc/engine'
require 'sassc/engine'
19 changes: 17 additions & 2 deletions lib/sassc/engine.rb
Expand Up @@ -6,18 +6,33 @@ class Engine
def initialize(input, options = {})
@input = input
@options = options
@custom_functions = []
end


def custom_function(signature, &block)
@custom_functions << [signature, block]
end

def render
ctx = SassC::Lib::Context.create(@input, @options)

unless @custom_functions.empty?
ctx.set_custom_functions @custom_functions
end

SassC::Lib.sass_compile(ctx)

if ctx[:error_status] != 0
raise SyntaxError.new("Sass error #{ctx[:error_message]}")
end

ctx[:output_string]
ensure
ctx && ctx.free
end
end
end
end

require "sassc/engine/color"
require "sassc/engine/list"
require "sassc/engine/number"
13 changes: 13 additions & 0 deletions lib/sassc/engine/color.rb
@@ -0,0 +1,13 @@
require 'ostruct'

module SassC
class Engine::Color < OpenStruct
def initialize(r=0, g=0, b=0, a=255)
super()
self.r = r
self.g = g
self.b = b
self.a = a
end
end
end
23 changes: 23 additions & 0 deletions lib/sassc/engine/list.rb
@@ -0,0 +1,23 @@
module SassC
class Engine::List < Array
SEPARATORS = [" ", ","]
DEFAULT_SEPARATOR = :" "

def initialize(arr, sep=nil)
super(arr)
self.separator = sep if sep
end

def separator
@separator || DEFAULT_SEPARATOR
end

def separator=(sep)
unless SEPARATORS.include? sep.to_s
raise "delimiter must be one of ` `, `,`"
end

@separator = sep.to_sym
end
end
end
12 changes: 12 additions & 0 deletions lib/sassc/engine/number.rb
@@ -0,0 +1,12 @@
require 'delegate'

module SassC
class Engine::Number < SimpleDelegator
attr_accessor :unit

def initialize(num, unit="")
super(num)
@unit = unit
end
end
end
24 changes: 9 additions & 15 deletions lib/sassc/lib.rb
@@ -1,31 +1,25 @@
require 'ffi'

require_relative 'lib/context'

module SassC
# Represents the exact wrapper around libsass
module Lib
extend FFI::Library
ffi_lib File.join(File.dirname(__FILE__), '../libsass.bundle')
ffi_lib "sass"

attach_function :sass_new_context, [], :pointer
attach_function :sass_new_file_context, [], :pointer
attach_function :sass_new_folder_context, [], :pointer

attach_function :sass_free_context, [:pointer], :void
attach_function :sass_free_file_context, [:pointer], :void
attach_function :sass_free_folder_context, [:pointer], :void

attach_function :sass_compile, [:pointer], :int32
attach_function :sass_compile_file, [:pointer], :int32
attach_function :sass_compile_folder, [:pointer], :int32

def self.to_char(string)
# get the number of bytes in the key
bytecount = string.unpack("C*").size

# create a pointer to memory and write the file to it
ptr = FFI::MemoryPointer.new(:char, bytecount)
ptr.put_bytes(0, string.dup, 0, bytecount)
end
end
end
end

require 'sassc/lib/context'
require 'sassc/lib/sass_value'
require 'sassc/lib/sass_c_function_descriptor'
61 changes: 47 additions & 14 deletions lib/sassc/lib/context.rb
Expand Up @@ -5,26 +5,59 @@ class Context < FFI::Struct
STYLES = %w(nested expanded compact compressed)
SOURCE_COMMENTS = %w(none default map)

layout :source_string, :pointer,
:output_string, :string,
:options, Options,
:error_status, :int,
:error_message, :string,
:c_functions, :pointer

# struct sass_context {
# const char* source_string;
# char* output_string;
# struct sass_options options;
# int error_status;
# char* error_message;
# struct Sass_C_Function_Data* c_functions;
# char** included_files;
# int num_included_files;
# };
layout :source_string, :pointer,
:output_string, :string,
:options, SassOptions,
:error_status, :int,
:error_message, :string,
:c_functions, :pointer,
:included_files, :pointer,
:num_included_files, :int

def self.create(input_string, options = {})
ptr = SassC::Lib.sass_new_context()
ctx = SassC::Lib::Context.new(ptr)

ctx[:source_string] = FFI::MemoryPointer.from_string(input_string || "")

ctx[:options][:output_style] = STYLES.index(options[:output_style] || "nested")
ctx[:options][:source_comments] = SOURCE_COMMENTS.index(options[:source_comments] || "none")
ctx[:options] = SassOptions.create(options)

ctx[:options][:include_paths] = FFI::MemoryPointer.from_string(options[:include_paths] || "")
ctx[:options][:image_path] = FFI::MemoryPointer.from_string(options[:image_path] || "")

ctx
end

def set_custom_functions(input_funcs)
num_funcs = input_funcs.count + 1
funcs_ptr = FFI::MemoryPointer.new(SassC::Lib::SassCFunctionDescriptor, num_funcs)

num_funcs.times.each do |i|
fn = SassC::Lib::SassCFunctionDescriptor.new(funcs_ptr + i * SassC::Lib::SassCFunctionDescriptor.size)

if input = input_funcs[i]
signature, block = input
fn[:signature] = FFI::MemoryPointer.from_string(signature)
fn[:function] = FFI::Function.new(SassC::Lib::SassValue.by_value, [SassC::Lib::SassValue.by_value]) do |arg|
ret = SassC::Lib::SassValue.new()
ret.from_ruby block.call arg.to_ruby
end
end

fn
end

self[:c_functions] = funcs_ptr
end

def free
SassC::Lib.sass_free_context(self)
end
end
end
end
10 changes: 10 additions & 0 deletions lib/sassc/lib/sass_c_function_descriptor.rb
@@ -0,0 +1,10 @@
module SassC::Lib
class SassCFunctionDescriptor < FFI::Struct
# struct Sass_C_Function_Descriptor {
# const char* signature;
# Sass_C_Function function;
# };
layout :signature, :pointer,
:function, :pointer
end
end
33 changes: 33 additions & 0 deletions lib/sassc/lib/sass_options.rb
@@ -0,0 +1,33 @@
module SassC::Lib
class SassOptions < FFI::Struct
STYLES = %w(nested expanded compact compressed)
SOURCE_COMMENTS = %w(none default map)

# struct sass_options {
# int output_style;
# int source_comments; // really want a bool, but C doesn't have them
# char* include_paths;
# char* image_path;
# };
layout :output_style, :int,
:source_comments, :int,
:include_paths, :pointer,
:image_path, :pointer

def self.create(options = {})
options = {
:output_style => "nested",
:source_comments => "none",
:image_path => "images",
:include_paths => ""
}.merge(options)

struct = SassOptions.new
struct[:output_style] = STYLES.index(options[:output_style])
struct[:source_comments] = SOURCE_COMMENTS.index(options[:source_comments])
struct[:image_path] = FFI::MemoryPointer.from_string(options[:image_path])
struct[:include_paths] = FFI::MemoryPointer.from_string(options[:include_paths])
struct
end
end
end

0 comments on commit ddb57b7

Please sign in to comment.