Permalink
Browse files

Use Rspec. Refactor, remove duplication and fix a bug. Prepare for ge…

…m release.
  • Loading branch information...
1 parent 960c447 commit 6fbc6c915d7f8c3c451f4dc4e040e096a6dd90ba @stevehodgkiss stevehodgkiss committed Mar 13, 2012
Showing with 409 additions and 442 deletions.
  1. +4 −0 .gitignore
  2. +1 −0 .rspec
  3. +3 −0 Gemfile
  4. +8 −0 Rakefile
  5. +19 −0 lumberjack.gemspec
  6. +63 −114 lumberjack.rb
  7. +311 −0 lumberjack_spec.rb
  8. +0 −324 lumberjack_test.rb
  9. +0 −4 rakefile.rb
View
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
View
1 .rspec
@@ -0,0 +1 @@
+--colour
View
@@ -0,0 +1,3 @@
+source "http://rubygems.org"
+
+gem "rspec"
View
@@ -0,0 +1,8 @@
+require "bundler/gem_tasks"
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec) do |s|
+ s.pattern = '*_spec.rb'
+end
+
+task :default => :spec
View
@@ -0,0 +1,19 @@
+# -*- encoding: utf-8 -*-
+Gem::Specification.new do |s|
+ s.name = "lumberjack"
+ s.version = "0.0.1"
+ s.authors = ["Ryan Allen", "Steve Hodgkiss", "John Barton", "James Dowling"]
+ s.email = ["ryan@yeahnah.org", "steve@hodgkiss.me", "jrbarton@gmail.com", "jamesd741@gmail.com"]
+ s.homepage = ""
+ s.summary = %q{Lumberjack is best summed up as a generic DSL for constructing object trees.}
+ s.description = %q{}
+
+ s.rubyforge_project = "lumberjack"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["."]
+
+ s.add_development_dependency "rspec"
+end
View
@@ -6,25 +6,28 @@ def self.construct(initial_scope = [], &block)
end
@@methods_to_keep = /^__/, /class/, /instance_eval/, /method_missing/,
- /instance_variable_(g|s)et/
+ /instance_variable_(g|s)et/, /instance_variables/, /inspect/, /send/,
+ /^object_id/, /^respond_to/
instance_methods.each do |m|
undef_method m unless @@methods_to_keep.find { |r| r.match m }
end
def initialize(initial_scope)
@initial_scope = initial_scope
+ @scope_stack ||= []
end
def __process(block)
- prepare_scope
+ @scope = [@initial_scope]
instance_eval(&block) if block
tree
rescue
raise $!
end
- def /(ignore_me) # syntatic sugar for scope resolution
+ # syntatic sugar for scope resolution
+ def /(ignore_me)
self
end
@@ -52,153 +55,99 @@ def prune(method, value)
def method_missing(*args, &block)
if still_modifying_scope?(args, block)
- push_to_scope_stack_and_return_self(args)
+ @scope_stack << args.first
else
- assign_to_current_scope(*args, &block)
+ assign_to_current_scope(args, block)
end
+ self
end
private
- def assign_to_current_scope(*args, &block)
- case current_scope_type
- when :instance
- assign_to_instance_with(*args, &block)
- when :array
- assign_to_array_with(*args, &block)
- end
- end
-
- def assign_to_array_with(*args, &block)
- klass = args.shift
- if within_a_scope?
- module_scope = @scope_stack.collect { |bit| classify bit.to_s }.join('::')
- instance = eval("#{module_scope}::#{classify klass.to_s}").new(*args)
- @scope_stack = nil
+ def assign_to_current_scope(args, block)
+ if current_scope.respond_to?(:<<)
+ assign_to_array_with(args, block)
else
- instance = eval(classify(klass.to_s)).new(*args)
+ assign_to_instance_with(args, block)
end
- current_scope << instance # add this instance to the scoped Array
- assign_accessors_within_scope(instance, &block) if block
- end
-
- def assign_accessors_within_scope(instance, &block)
- evaluate_block_within_context(instance, &block)
- end
-
- def assign_array_of_subvalues_to_accessor(accessor, &block)
- evaluate_block_within_context(current_accessor(accessor), &block)
end
- def evaluate_block_within_context(accessor, &block)
- append_scope_with accessor
- instance_eval(&block)
- jump_out_of_scope
- end
-
- def within_a_scope?
- @scope_stack and @scope_stack.any?
- end
-
- def assign_to_instance_with(*args, &block)
+ def assign_to_instance_with(args, block)
accessor = args.shift
- case instance_assignment_behaviour_for(accessor, args, block)
- when :assign_subvalues_to_instance
- assign_subvalues_to_instance(accessor, args, &block)
- when :assign_array_of_subvalues_to_accessor
- assign_array_of_subvalues_to_accessor(accessor, &block)
- when :assign_directly_to_accessor
- current_scope.send("#{accessor}=", *args)
- when :assign_array_directly_to_accessor
- current_scope.send("#{accessor}=", args)
- else
- raise "unknown assignment behaviour '#{assignment_behaviour_for(accessor)}' for accessor '#{acccessor}'"
- end
- end
-
- def current_accessor(accessor)
- if current_accessor_undefined?(accessor)
- set_current_accessor_as_empty_array(accessor)
+ if accessor.to_s[-1].chr == '!'
+ # create class based on the accessor name
+ assign_subvalues_to_instance(accessor, args, block)
+ elsif block and args.empty?
+ # accessor is to refer to an array
+ current_array_instance = get_accessor_value(accessor)
+ evaluate_block_within_context(current_array_instance, block)
+ elsif args.length == 1
+ # splat to avoid array and directly assign the argument
+ current_scope.send("#{accessor}=", *args)
+ else
+ # assign array
+ current_scope.send("#{accessor}=", args)
end
- current_scope.send("#{accessor}")
end
- def set_current_accessor_as_empty_array(accessor)
- current_scope.send("#{accessor}=", [])
+ def assign_to_array_with(args, block)
+ klass = args.shift
+ instance = build_class(klass, args)
+ current_scope << instance # add this instance to the scoped Array
+ evaluate_block_within_context(instance, block) if block
end
- def current_accessor_undefined?(accessor)
- current_scope.send("#{accessor}").nil?
+ def assign_subvalues_to_instance(accessor, args, block)
+ accessor_class = accessor.to_s[0...-1]
+ instance = build_class(accessor_class, args)
+ instance.parent = current_scope if instance.respond_to?(:parent=)
+ current_scope.send("#{accessor_class}=", instance)
+ evaluate_block_within_context(instance, block) if block
end
- def assign_subvalues_to_instance(accessor, args, &block)
- instance = eval(classify(accessor.to_s[0...-1])).new(args)
- current_scope.send("#{accessor.to_s[0...-1]}=", instance)
- set_accessors_within_scope(instance, &block) if block
+ def build_class(klass, args)
+ @scope_stack << klass
+ scoped_class = @scope_stack.join('/')
+ @scope_stack = []
+ classify(scoped_class).new(*args)
end
- def set_accessors_within_scope(instance, &block)
- append_scope_with instance
+ def evaluate_block_within_context(accessor, block)
+ @scope.push accessor
instance_eval(&block)
- jump_out_of_scope
+ @scope.pop
end
- def instance_assignment_behaviour_for(accessor, args, block)
- if accessor.to_s[-1].chr == '!' #accessor is an actual instance
- :assign_subvalues_to_instance
- elsif block and args.empty? #accessor is to refer to an array
- :assign_array_of_subvalues_to_accessor
- elsif args.length == 1
- :assign_directly_to_accessor
- else
- :assign_array_directly_to_accessor
+ def get_accessor_value(accessor)
+ if current_scope.send("#{accessor}").nil?
+ current_scope.send("#{accessor}=", [])
end
- end
-
-
- def current_scope_type
- # we're assuming any scope that responds to << must be a collection,
- current_scope.respond_to?(:<<) ? :array : :instance
- end
-
- def push_to_scope_stack_and_return_self(args)
- (@scope_stack ||= []) << args[0]
- self
+ current_scope.send("#{accessor}")
end
def still_modifying_scope?(args, block)
# if we only have one arg, and no block, then we're trying to build a
# module scope, i.e. a/b/c/d would resolve to A::B::C::D,
- args.length == 1 and block.nil?
- end
-
- def prepare_scope
- @scope = [@initial_scope]
- end
-
- def append_scope_with(new_scope)
- scope.push new_scope
- end
-
- def jump_out_of_scope
- scope.pop
+ args.length == 1 && block.nil?
end
def current_scope
- scope.last
+ @scope.last
end
def tree
- scope.first
- end
-
- def scope
- @scope
+ @scope.first
end
- def classify(str)
- camels = str.split('_')
- camels.collect { |c| c.capitalize }.join
+ # Turns an underscored path into the class it represents
+ #
+ # Usage: classify("some/cool_klass") => Some::CoolKlass
+ def classify(class_name)
+ klass = class_name.split('/').collect do |component|
+ camels = component.split('_')
+ camels.collect { |c| c.capitalize }.join
+ end.join('::')
+ eval("::#{klass}")
end
-end
+end
Oops, something went wrong.

0 comments on commit 6fbc6c9

Please sign in to comment.