From 4977b1b7de9c34b77e4f1e706fdead66ea5c01e0 Mon Sep 17 00:00:00 2001 From: eric thul Date: Fri, 1 Jun 2012 20:16:42 -0400 Subject: [PATCH] Implementing the RoyFilter The RoyFilter compiles files written in the Roy language (http://roy.brianmckenna.org) to JavaScript as part of the asset pipeline. This filter depends on the roy-lang gem. It has been added a dev dependency. An example using the filter in an Assetfile: output "public" input "assets" do match "*.roy" do roy end end Also, therubyracer gem was added as a dev depedency because the less files would not compile without it. Also, the coffee script filter's spec was modified since the error message on the spec testing invalid input gave a slighly different message than what the spec was expecting. --- .gitignore | 1 + lib/rake-pipeline-web-filters.rb | 1 + lib/rake-pipeline-web-filters/helpers.rb | 6 +++ lib/rake-pipeline-web-filters/roy_filter.rb | 56 +++++++++++++++++++++ rake-pipeline-web-filters.gemspec | 2 + spec/coffee_script_filter_spec.rb | 2 +- spec/helpers_spec.rb | 7 +++ spec/roy_filter_spec.rb | 45 +++++++++++++++++ spec/spec_helper.rb | 4 ++ 9 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 lib/rake-pipeline-web-filters/roy_filter.rb create mode 100644 spec/roy_filter_spec.rb diff --git a/.gitignore b/.gitignore index d87d4be..d9ee225 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ *.gem *.rbc +*.swp .bundle .config .yardoc diff --git a/lib/rake-pipeline-web-filters.rb b/lib/rake-pipeline-web-filters.rb index f2d6456..357d57c 100644 --- a/lib/rake-pipeline-web-filters.rb +++ b/lib/rake-pipeline-web-filters.rb @@ -25,4 +25,5 @@ module Filters require "rake-pipeline-web-filters/chained_filter" require "rake-pipeline-web-filters/less_filter" require "rake-pipeline-web-filters/handlebars_filter" +require "rake-pipeline-web-filters/roy_filter" require "rake-pipeline-web-filters/helpers" diff --git a/lib/rake-pipeline-web-filters/helpers.rb b/lib/rake-pipeline-web-filters/helpers.rb index 594ea79..4862af2 100644 --- a/lib/rake-pipeline-web-filters/helpers.rb +++ b/lib/rake-pipeline-web-filters/helpers.rb @@ -92,6 +92,12 @@ def less(*args, &block) def handlebars(*args, &block) filter(Rake::Pipeline::Web::Filters::HandlebarsFilter, *args, &block) end + + # Add a new {RoyFilter} to the pipeline. + # @see RoyFilter#initialize + def roy(*args, &block) + filter(Rake::Pipeline::Web::Filters::RoyFilter, *args, &block) + end end module ProjectHelpers diff --git a/lib/rake-pipeline-web-filters/roy_filter.rb b/lib/rake-pipeline-web-filters/roy_filter.rb new file mode 100644 index 0000000..e103a38 --- /dev/null +++ b/lib/rake-pipeline-web-filters/roy_filter.rb @@ -0,0 +1,56 @@ +require 'rake-pipeline-web-filters/filter_with_dependencies' + +module Rake::Pipeline::Web::Filters + # Public: The RoyFilter compiles scripts written in Roy to JavaScript. + # + # This filter depends on the roy-lang gem. + # + # Examples + # + # The following is an example Assetfile usage. + # + # output "public" + # + # input "assets" do + # match "*.roy" do + # roy + # end + # end + class RoyFilter < Rake::Pipeline::Filter + include Rake::Pipeline::Web::Filters::FilterWithDependencies + + # Public: Returns the hash of options used when compiling. + attr_reader :options + + # Public: Initializes a RoyFilter. + # + # options - The Hash of options to use when compiling (default: {}): + # See the roy-lang gem for available options. + # block - A block to map input names to ouput names (defaults to + # mapping .roy files to .js). + def initialize(options = {}, &block) + super &(block || ->input {input.sub(/\.roy\z/, ".js")}) + @options = options + end + + protected + # Internal: Generates a JavaScript output file containing each + # compiled input. + # + # inputs - Array of FileWrappers of Roy files. + # output - A FileWrapper of a JavaScript file. + def generate_output(inputs, output) + inputs.each do |input| + output.write Roy.compile(input.read, @options) + end + end + + private + # Internal: Defines the external dependencies of this filter. + # + # Returns an Array of the dependencies. + def external_dependencies + ["roy-lang"] + end + end +end diff --git a/rake-pipeline-web-filters.gemspec b/rake-pipeline-web-filters.gemspec index 02171e6..3f2a31e 100644 --- a/rake-pipeline-web-filters.gemspec +++ b/rake-pipeline-web-filters.gemspec @@ -27,5 +27,7 @@ Gem::Specification.new do |gem| gem.add_development_dependency "yui-compressor" gem.add_development_dependency "uglifier" gem.add_development_dependency "less" + gem.add_development_dependency "therubyracer" gem.add_development_dependency "json" + gem.add_development_dependency "roy-lang" end diff --git a/spec/coffee_script_filter_spec.rb b/spec/coffee_script_filter_spec.rb index b948846..33e6b31 100644 --- a/spec/coffee_script_filter_spec.rb +++ b/spec/coffee_script_filter_spec.rb @@ -102,7 +102,7 @@ def setup_filter(filter) tasks = filter.generate_rake_tasks lambda { tasks.each(&:invoke) - }.should raise_error(ExecJS::RuntimeError, /Error compiling input.coffee. reserved word "function" on line 1/i) + }.should raise_error(ExecJS::RuntimeError, /Error compiling input.coffee\..*reserved word "function" on line 1/i) end end diff --git a/spec/helpers_spec.rb b/spec/helpers_spec.rb index 13770b2..0ecfff8 100644 --- a/spec/helpers_spec.rb +++ b/spec/helpers_spec.rb @@ -95,6 +95,13 @@ def filter filter.should be_kind_of(Rake::Pipeline::Web::Filters::HandlebarsFilter) end end + + describe "#roy" do + it "creates a RoyFilter" do + dsl.roy + filter.should be_kind_of(Rake::Pipeline::Web::Filters::RoyFilter) + end + end end describe "ProjectHelpers" do diff --git a/spec/roy_filter_spec.rb b/spec/roy_filter_spec.rb new file mode 100644 index 0000000..e4f1a63 --- /dev/null +++ b/spec/roy_filter_spec.rb @@ -0,0 +1,45 @@ +describe "RoyFilter" do + let(:file_wrapper_class){Rake::Pipeline::SpecHelpers::MemoryFileWrapper} + let(:rake_app){Rake::Application.new} + + let(:encoding){"UTF-8"} + let(:input_path){"/in"} + let(:output_path){"/out"} + let(:input_name){"a.roy"} + let(:output_name){"a.js"} + + let(:input_file){file_wrapper_class.new(input_path, input_name, encoding, input)} + let(:output_file){file_wrapper_class.new(output_path, output_name, encoding)} + + subject { + filter = Rake::Pipeline::Web::Filters::RoyFilter.new(options) + filter.file_wrapper_class = file_wrapper_class + filter.input_files = [input_file] + filter.output_root = output_path + filter.rake_application = rake_app + filter + } + + describe "#generate_output" do + context "when default options are used" do + let(:options){{}} + let(:output){<<-JS.gsub(/^\s*/,"") + (function() { + var x = 10; + })(); + JS + } + context "when the input is valid" do + let(:input){"let x = 10"} + before{subject.generate_rake_tasks.each(&:invoke)} + specify{subject.output_files.should == [output_file]} + specify{file_wrapper_class.files["#{output_path}/#{output_name}"].body.should == output} + specify{file_wrapper_class.files["#{output_path}/#{output_name}"].encoding.should == encoding} + end + context "when the input is invalid" do + let(:input){"var = x, 10"} + specify{->{subject.generate_rake_tasks.each(&:invoke)}.should raise_error} + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 8e192e2..d55eed9 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -101,4 +101,8 @@ def tmp config.after do Dir.chdir(original) end + + config.treat_symbols_as_metadata_keys_with_true_values = true + config.run_all_when_everything_filtered = true + config.filter_run :focus end