diff --git a/README.md b/README.md index a0d75a3..c556f68 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,31 @@ Rscons::Environment.new do |env| end ``` +### Example: Custom Builder Using Environment#add_builder() + +The `add_builder` method of the `Rscons::Environment` class optionally allows +you to define and register a builder by providing a name and action block. This +can be useful if the builder you are trying to define is easily expressed as a +short ruby procedure. When `add_builder` is called in this manner a new builder +will be registered with the environment with the given name. When this builder +is used it will call the provided block in order to build the target. + +```ruby +Rscons::Environment.new do |env| + env.add_builder(:JsonToYaml) do |target, sources, cache, env, vars| + unless cache.up_to_date?(target, :JsonToYaml, sources, env) + cache.mkdir_p(File.dirname(target)) + File.open(target, 'w') do |f| + f.write(YAML.dump(JSON.load(IO.read(sources.first)))) + end + cache.register_build(target, :JsonToYaml, sources, env) + end + target + end + env.JsonToYaml('foo.yml','foo.json') +end +``` + ### Example: Using different compilation flags for some sources ```ruby diff --git a/build_tests/json_to_yaml/foo.json b/build_tests/json_to_yaml/foo.json new file mode 100644 index 0000000..7ba1b79 --- /dev/null +++ b/build_tests/json_to_yaml/foo.json @@ -0,0 +1 @@ +{ "key": "value" } diff --git a/lib/rscons.rb b/lib/rscons.rb index a566821..30b3306 100644 --- a/lib/rscons.rb +++ b/lib/rscons.rb @@ -13,6 +13,7 @@ require_relative "rscons/builders/library" require_relative "rscons/builders/object" require_relative "rscons/builders/preprocess" require_relative "rscons/builders/program" +require_relative "rscons/builders/simple_builder" # Namespace module for rscons classes module Rscons diff --git a/lib/rscons/builders/simple_builder.rb b/lib/rscons/builders/simple_builder.rb new file mode 100644 index 0000000..50a31dc --- /dev/null +++ b/lib/rscons/builders/simple_builder.rb @@ -0,0 +1,37 @@ +module Rscons + module Builders + # A Generic builder class whose name and operation is defined at + # instantiation. + class SimpleBuilder < Builder + # The name of this builder when registered in an environment + attr_reader :name + + # Create a new builder with the given name and action. + # + # @param name [String,Symbol] The name of the builder when registered. + # @param block [Block] + # The action to perform when the builder is processed. The provided + # block must return the target file on success or false on failure. + # The provided block should have the same signature as {Builder#run}. + def initialize(name, &block) + @name = name.to_s + @block = block + end + + # Run the builder to produce a build target. + # + # @param target [String] Target file name. + # @param sources [Array] Source file name(s). + # @param cache [Cache] The Cache object. + # @param env [Environment] The Environment executing the builder. + # @param vars [Hash,VarSet] Extra construction variables. + # + # @return [String,false] + # Name of the target file on success or false on failure. + def run(target, sources, cache, env, vars) + @block.call(target, sources, cache, env, vars) + end + end + end +end + diff --git a/lib/rscons/environment.rb b/lib/rscons/environment.rb index 6a920b7..dc5da90 100644 --- a/lib/rscons/environment.rb +++ b/lib/rscons/environment.rb @@ -120,10 +120,26 @@ module Rscons # Add a {Builder} object to the Environment. # - # @param builder [Builder] The {Builder} object to add. + # @overload add_builder(builder) + # Registers a builder with the environment + # @param builder [Builder] An instance of the builder to register. + # + # @overload add_builder(builder,&action) + # Register a new {Builders::SimpleBuilder} with the environment. + # + # @param builder [String,Symbol] + # The name of the builder to add. + # + # @param action [Block] + # A block that will be called when the builder is executed to generate + # a target file. The provided block should have the same prototype as + # {Rscons::Builder#run} # # @return [void] - def add_builder(builder) + def add_builder(builder, &action) + if not builder.is_a? Rscons::Builder + builder = Rscons::Builders::SimpleBuilder.new(builder, &action) + end @builders[builder.name] = builder var_defs = builder.default_variables(self) if var_defs diff --git a/spec/build_tests_spec.rb b/spec/build_tests_spec.rb index 74d4e28..d00b104 100644 --- a/spec/build_tests_spec.rb +++ b/spec/build_tests_spec.rb @@ -249,6 +249,27 @@ describe Rscons do ] end + it 'supports simple builders' do + test_dir('json_to_yaml') + Rscons::Environment.new do |env| + require 'json' + require 'yaml' + env.add_builder(:JsonToYaml) do |target, sources, cache, env, vars| + unless cache.up_to_date?(target, :JsonToYaml, sources, env) + cache.mkdir_p(File.dirname(target)) + File.open(target, 'w') do |f| + f.write(YAML.dump(JSON.load(IO.read(sources.first)))) + end + cache.register_build(target, :JsonToYaml, sources, env) + end + target + end + env.JsonToYaml('foo.yml','foo.json') + end + expect(File.exists?('foo.yml')).to be_truthy + expect(IO.read('foo.yml')).to eq("---\nkey: value\n") + end + it 'cleans built files' do test_dir('build_dir') Rscons::Environment.new do |env| diff --git a/spec/rscons/builders/simple_builder_spec.rb b/spec/rscons/builders/simple_builder_spec.rb new file mode 100644 index 0000000..0031221 --- /dev/null +++ b/spec/rscons/builders/simple_builder_spec.rb @@ -0,0 +1,19 @@ +module Rscons + module Builders + describe SimpleBuilder do + let(:env) {Environment.new} + + it "should create a new builder with the given name (as a symbol) and action" do + builder = Rscons::Builders::SimpleBuilder.new(:Foo) { 0x1234 } + expect(builder.name).to eq("Foo") + expect(builder.run(1,2,3,4,5)).to eq(0x1234) + end + + it "should create a new builder with the given name (as a string) and action" do + builder = Rscons::Builders::SimpleBuilder.new("Foo") { 0x1234 } + expect(builder.name).to eq("Foo") + expect(builder.run(1,2,3,4,5)).to eq(0x1234) + end + end + end +end diff --git a/spec/rscons/environment_spec.rb b/spec/rscons/environment_spec.rb index 588608e..5d1045f 100644 --- a/spec/rscons/environment_spec.rb +++ b/spec/rscons/environment_spec.rb @@ -72,6 +72,13 @@ module Rscons env.add_builder(Rscons::Builders::Object.new) expect(env.builders.keys).to eq ["Object"] end + + it "adds a new simple builder to the list of builders" do + env = Environment.new(exclude_builders: true) + expect(env.builders.keys).to eq [] + env.add_builder(:Foo) {} + expect(env.builders.keys).to eq ["Foo"] + end end describe "#get_build_fname" do