Skip to content

Commit

Permalink
adding a chain of tag resolution sources
Browse files Browse the repository at this point in the history
  • Loading branch information
christfo committed Mar 14, 2012
1 parent 3bcb127 commit 8e1dca5
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 34 deletions.
8 changes: 4 additions & 4 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ source "http://rubygems.org"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
gem "rspec", "~> 2.8.0"
gem "rdoc", "~> 3.12"
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.8.3"
gem "rspec", ">= 2.8.0"
gem "rdoc", ">= 3.12"
gem "bundler", ">= 1.0.0"
gem "jeweler", ">= 1.8.3"
gem 'simplecov', :platforms => :mri_19
gem 'rcov', :platforms => :mri_18
end
Expand Down
67 changes: 40 additions & 27 deletions lib/detagger.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,51 +7,64 @@
module Detagger
attr_accessor :tagex

def drill_down_ref(txt,target = self)
# create a chain of objects that will be used to discover the value behind the tags.
# This will be ordered, favouring the first item in preference to later ones.
def set_detag_chain(*args)
@detag_chain = args
end

def detag_chain
(@detag_chain || self)
end

def drill_down_ref(txt,targets = detag_chain)
return unless txt
parm = txt.chomp(":").to_sym
begin
new_txt = target.send(parm)
raise "Self Reference" if new_txt == txt
new_txt
rescue NoMethodError
txt
[*targets].each do |target|
begin
new_txt = target.send(parm)
raise "Self Reference" if new_txt == txt
return new_txt
rescue NoMethodError
end
end
txt
end

def detag( value, target = self, resolved = [] )
def detag( value, targets = detag_chain, resolved = [] )
@tagex ||= /([^\/:]+:)/
[*targets].each do |target|
if ( value.respond_to? :call )
# manipulates self so that it is called with 'this' and not he context of the proc when defined
value = target.instance_eval &value
end

if ( value.respond_to? :call )
# manipulates self so that it is called with 'this' and not he context of the proc when defined
value = target.instance_eval &value
end

if value && value.is_a?(String)
value = value.shatter(@tagex).flatten.map do |mtch|
if mtch =~ @tagex
raise "Circular Reference" if resolved.include? mtch
new_value = drill_down_ref(mtch,target)
mtch == new_value ? new_value : detag(new_value, target, resolved + [mtch] )
if value && value.is_a?(String)
value = value.shatter(@tagex).flatten.map do |mtch|
if mtch =~ @tagex
raise "Circular Reference" if resolved.include? mtch
new_value = drill_down_ref(mtch,targets)
mtch == new_value ? new_value : detag(new_value, [target], resolved + [mtch] )
else
mtch
end
end
if (value.uniq == [nil])
value = nil
else
mtch
value = value.join
end
end
if (value.uniq == [nil])
value = nil
else
value = value.join
end
end
value
end

def method_missing( method, *args, &blk )
access, orig_method = *method.to_s.scan(/^(detag|raw)_(.+)$/).flatten
unless orig_method && self.respond_to?(orig_method.to_sym )
unless orig_method && target = [*detag_chain].find {|t| t.respond_to?( orig_method.to_sym )}
super(method,*args,&blk)
else
rawval = self.send( orig_method, *args, &blk )
rawval = target.send( orig_method, *args, &blk )
(access == "detag") ? detag( rawval ) : rawval
end
end
Expand Down
32 changes: 29 additions & 3 deletions spec/detagger_spec.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
require "ostruct"

describe Detagger do
before( :each ) do
@options = Class.new do
def bob; "henry" end
def bob; "henry:" end
def sue; "mary" end
def alfy; "sue:" end
def jess; "sue:/bob:some text/bob:text" end
Expand Down Expand Up @@ -36,7 +37,7 @@ def mike; "sue:soph:sue:jim:" end
end

it "will give a value for inputs" do
@options.bob.should == "henry"
@options.bob.should == "henry:"
@options.sue.should == "mary"
end

Expand All @@ -55,7 +56,7 @@ def mike; "sue:soph:sue:jim:" end
end

it "will support multiple tags in a value" do
@options.detag_jess.should == "mary/henrysome text/henrytext"
@options.detag_jess.should == "mary/henry:some text/henry:text"
end

it "will pass through unrecognised tags a plain text" do
Expand All @@ -82,6 +83,31 @@ def mike; "sue:soph:sue:jim:" end
@options.raw_soph.should == nil
@options.detag_soph.should == nil
@options.detag_matt.should == nil
end

it "will absorbe nil values inside a string" do
@options.detag_mike.should == "marymary"
end

it "will search for tags down a cahin of objects" do
second = OpenStruct.new
second.nick = "Found!"
@options.set_detag_chain( @options, second )
@options.detag_nick.should == "Found!"
end

it "will look for tags in strict chain order" do
second = OpenStruct.new
second.sue = "not this one"
@options.set_detag_chain( @options, second )
@options.detag_sue.should_not == "not this one"
@options.detag_sue.should == "mary"
end

it "will compose missing tags from both sources" do
second = OpenStruct.new
second.henry = "correct"
@options.set_detag_chain( @options, second )
@options.detag_bob.should == "correct"
end
end

0 comments on commit 8e1dca5

Please sign in to comment.