jarrett-quarto 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README CHANGED
@@ -1,9 +1,14 @@
1
1
  Quarto is a Ruby framework for generating collections of documents from XML. Potential applications
2
- include web sites and e-books. It's built on top of ERB and REXML.
2
+ include web sites and e-books. It's built on top of ERB and REXML. It works as a standalone
3
+ application and inside Rails.
3
4
 
4
5
  Quarto was built with HTML output in mind, but there's nothing to prevent you from outputting
5
6
  to any other format. You could even output to an interpolated scripting language like PHP.
6
7
 
8
+ As of the inception of Quarto, there is no cross-platform XSLT gem. So, Quarto comes with its
9
+ own alternative to XSLT in the form of the Tranformer class and the TransformationHelper
10
+ module.
11
+
7
12
  Why Quarto?
8
13
  ===========
9
14
 
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gemspec.authors = ['Jarrett Colby']
11
11
  gemspec.files = FileList['[A-Z]*', '{bin,lib,test}/**/*']
12
12
  gemspec.executables = 'quarto'
13
- gemspec.add_dependency('activesupport', '>= 2.3.2')
13
+ gemspec.add_dependency('activesupport', '~> 2.3.2')
14
14
  end
15
15
  rescue LoadError
16
16
  puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.0
1
+ 1.4.0
@@ -124,8 +124,15 @@ module Quarto
124
124
  end
125
125
  if element_attrs = self.class.read_inheritable_attribute(:element_attrs)
126
126
  element_attrs.each do |el_name|
127
- raise ArgumentError, "Expected <#{@element.name}> to have child <#{el_name}>" if @element.elements[el_name.to_s].nil?
128
- @attributes[el_name.to_sym] = typecast_text(@element.elements[el_name.to_s].text)
127
+ if child_el = @element.elements[el_name.to_s]
128
+ if child_el.elements.empty?
129
+ @attributes[el_name.to_sym] = typecast_text(child_el.text)
130
+ else
131
+ @attributes[el_name.to_sym] = child_el
132
+ end
133
+ else
134
+ @attributes[el_name.to_sym] = nil
135
+ end
129
136
  end
130
137
  end
131
138
  if text_attr = self.class.read_inheritable_attribute(:text_attr)
@@ -41,7 +41,7 @@ module Quarto
41
41
  # This class responds to all the directives that are available for use within
42
42
  # a generate.rb file.
43
43
  class Generator
44
- include UrlHelper
44
+ include Quarto::UrlHelper
45
45
 
46
46
  # Sets the name of the default layout file in the layouts directory. If
47
47
  # default_layout isn't specified, the default layout is the first file matching <tt>default.*</tt>.
@@ -130,7 +130,7 @@ module Quarto
130
130
  def render_to_s(template, locals, options = {})
131
131
  require urls_file_path
132
132
 
133
- mixins = [Quarto::ProjectUrls, Quarto::RailsHelper, Quarto::UrlHelper]
133
+ mixins = [Quarto::ProjectUrls, Quarto::RailsHelper, Quarto::UrlHelper, Quarto::TransformationHelper]
134
134
 
135
135
  page_template_path = "#{@project_path}/pages/#{template}"
136
136
  page_template = ERB.new(File.read(page_template_path))
@@ -0,0 +1,103 @@
1
+ module Quarto
2
+ class HtmlTransformer < Transformer
3
+ HTML_ELEMENTS = %w(
4
+ a
5
+ abbr
6
+ acronym
7
+ address
8
+ applet
9
+ area
10
+ b
11
+ base
12
+ basefont
13
+ bdo
14
+ big
15
+ blockquote
16
+ body
17
+ br
18
+ button
19
+ caption
20
+ center
21
+ cite
22
+ code
23
+ col
24
+ colgroup
25
+ dd
26
+ del
27
+ dfn
28
+ dir
29
+ div
30
+ dl
31
+ dt
32
+ em
33
+ fieldset
34
+ font
35
+ form
36
+ frame
37
+ frameset
38
+ h1
39
+ h2
40
+ h3
41
+ h4
42
+ h5
43
+ h6
44
+ head
45
+ hr
46
+ html
47
+ i
48
+ iframe
49
+ img
50
+ input
51
+ ins
52
+ isindex
53
+ kbd
54
+ label
55
+ legend
56
+ li
57
+ link
58
+ map
59
+ menu
60
+ meta
61
+ noframes
62
+ noscript
63
+ object
64
+ ol
65
+ optgroup
66
+ option
67
+ p
68
+ param
69
+ pre
70
+ q
71
+ s
72
+ samp
73
+ script
74
+ select
75
+ small
76
+ span
77
+ strike
78
+ strong
79
+ style
80
+ sub
81
+ sup
82
+ table
83
+ tbody
84
+ td
85
+ textarea
86
+ tfoot
87
+ th
88
+ thead
89
+ title
90
+ tr
91
+ tt
92
+ u
93
+ ul
94
+ var
95
+ )
96
+
97
+ protected
98
+
99
+ def literal?(element)
100
+ HTML_ELEMENTS.include?(element.name)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,29 @@
1
+ module Quarto
2
+ module TransformationHelper
3
+ # Tranforms the children of +element+ using
4
+ # an instance of +transformer_class+ and returns
5
+ # a string representation of the result.
6
+ #
7
+ # +transformer_class+ must be a subclass of
8
+ # Quarto::Transformer or <tt>nil</tt>. If it's
9
+ # <tt>nil</tt> (which is the default), the default
10
+ # subclass will be used. The default subclass is set
11
+ # in <tt>generate.rb</tt> as follows:
12
+ #
13
+ # config(:default_transformer_class, YourSubclass)
14
+ #
15
+ # If you do not specify a default class,
16
+ # <tt>HtmlTransformer</tt> will be used.
17
+ def transform_xml(element, transformer_class = Quarto::HtmlTransformer)
18
+ raise ArgumentError, "Expected REXML::Element but got #{element.inspect}" unless element.is_a?(REXML::Element)
19
+ class_error = "Expected subclass of Tranformer but got #{transformer_class.inspect}"
20
+ raise ArgumentError, class_error unless transformer_class.is_a?(Class)
21
+ klass = transformer_class
22
+ while klass != Quarto::Transformer and klass != Object
23
+ klass = klass.superclass
24
+ end
25
+ raise ArgumentError, class_error unless Quarto::Transformer == klass
26
+ transformer_class.new.transform(element)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,143 @@
1
+ module Quarto
2
+ # This abstract base class is a substitute for XSLT. Its
3
+ # <tt>transform</tt> method takes a single
4
+ # <tt>REXML::Element</tt> and applies rules defined in
5
+ # the subclass.
6
+ #
7
+ # To define those rules, you subclass Transformer and
8
+ # write methods to handle each element type. For example:
9
+ #
10
+ # class MyTranformer < Quarto::Transformer
11
+ # # This method will handle all <book> elements
12
+ # def transform_book(book_element)
13
+ # # Return whatever string you like
14
+ # # raise_on_unrecognized_element is provided
15
+ # # so that you can pass it to recursive_transform
16
+ # # if necessary.
17
+ # end
18
+ # end
19
+ class Transformer
20
+ # Macro to define the <tt>literal?</tt> method. Accepts
21
+ # one or more element names.
22
+ #
23
+ # Example:
24
+ #
25
+ # class MyTransformer < Quarto::Transformer
26
+ # literals 'div', 'p', 'a'
27
+ # end
28
+ #
29
+ # The above is equivalent to:
30
+ #
31
+ # class MyTransformer < Quarto::Transformer
32
+ # def literal?(element)
33
+ # ['div', 'p', 'a'].include?(element.name)
34
+ # end
35
+ # end
36
+ def self.literals(*args)
37
+ class_eval(%Q(
38
+ def literal?(element)
39
+ [#{args.collect { |e| "'#{e}'" }.join(',')}].include?(element.name)
40
+ end
41
+ ))
42
+ end
43
+
44
+ # Recursively applies the transformation rules
45
+ # you've defined to +element+ and its children,
46
+ # returning the results as a string. Depending
47
+ # on the rules you've set up, the result may
48
+ # be XML or something else altogether.
49
+ #
50
+ # +element+ must be a <tt>REXML::Element</tt>.
51
+ #
52
+ # By default, unrecognized elements (and all their
53
+ # descendants) will be ommited from the result tree.
54
+ #
55
+ # However, you can cause these unrecognized elements to
56
+ # raise an exception by setting +raise_on_unrecognized_element+
57
+ # to <tt>true</tt>.
58
+ def transform(element, raise_on_unrecognized_element = false)
59
+ raise ArgumentError, "Expected REXML::Element but got #{element.inspect}" unless element.is_a?(REXML::Element)
60
+ if element.is_a?(REXML::Document)
61
+ recursive_transform(element.root, raise_on_unrecognized_element)
62
+ else
63
+ recursive_transform(element, raise_on_unrecognized_element)
64
+ end
65
+ end
66
+
67
+ protected
68
+
69
+ def content_tag(tag_name, *args) # :nodoc:
70
+ if args.last.is_a?(Hash)
71
+ attributes = args.pop
72
+ else
73
+ attributes = {}
74
+ end
75
+ if args.empty?
76
+ if block_given?
77
+ contents = yield
78
+ else
79
+ contents = nil
80
+ end
81
+ else
82
+ contents = args[0]
83
+ end
84
+ output = "<#{tag_name}"
85
+ attributes.each do |attr, value|
86
+ output << " #{attr}=\"#{value}\""
87
+ end
88
+ if contents.nil? or contents.empty?
89
+ output << '/>'
90
+ else
91
+ output << ">#{contents}</#{tag_name}>"
92
+ end
93
+ end
94
+
95
+ # This method is meant to be overriden in subclasses. The
96
+ # default implementation always returns false.
97
+ #
98
+ # When <tt>tranform</tt> is called, each descendant element
99
+ # is passed to <tt>literal?</tt>. If it returns true,
100
+ # the descdant is added to the result tree with the same
101
+ # tag. If not, the <tt>Transformer</tt> will look for a
102
+ # custom tranform method for that element. If none is found,
103
+ # what happens next depends on the value of
104
+ # <tt>raise_on_unrecognized_element</tt> in <tt>transform</tt>.
105
+ # If it's true, an exception will be raised. Otherwise, the
106
+ # element and its descendant will be ommitted from the result
107
+ # tree.
108
+ #
109
+ # If <tt>literal?</tt> returns true for an element,
110
+ # its descendant elements will not be added to the tree
111
+ # verbatim, but will instead be subjected to the same
112
+ # transformation process as everything else.
113
+ #
114
+ # See <tt>HtmlTransformer</tt> for an example implementation.
115
+ def literal?(element)
116
+ false
117
+ end
118
+
119
+ # Recursively transform the +element+ and all its children,
120
+ # returning a string. Custom transform methods often call
121
+ # this method.
122
+ def recursive_transform(element, raise_on_unrecognized_element)
123
+ if element.is_a?(REXML::Element)
124
+ if respond_to?("transform_#{element.name}")
125
+ send("transform_#{element.name}", element, raise_on_unrecognized_element)
126
+ elsif literal?(element)
127
+ contents = element.children.inject('') do |result, child|
128
+ result + recursive_transform(child, raise_on_unrecognized_element)
129
+ end
130
+ content_tag(element.name, contents, element.attributes)
131
+ elsif raise_on_unrecognized_element
132
+ raise UnrecognizedElementError, "Unrecognized element: #{element.name}"
133
+ else
134
+ ''
135
+ end
136
+ else
137
+ element.to_s
138
+ end
139
+ end
140
+ end
141
+
142
+ class UnrecognizedElementError < RuntimeError; end
143
+ end
data/lib/quarto.rb CHANGED
@@ -15,6 +15,9 @@ require 'quarto/element_wrapper'
15
15
  require 'quarto/children'
16
16
  require 'quarto/rendering'
17
17
  require 'quarto/generator'
18
+ require 'quarto/transformer'
19
+ require 'quarto/html_transformer'
20
+ require 'quarto/transformation_helper'
18
21
  require 'quarto/init_project'
19
22
 
20
23
  # Quarto is a Ruby framework for generating collections of documents from XML. Potential applications
data/quarto.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{quarto}
5
- s.version = "1.3.0"
5
+ s.version = "1.4.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Jarrett Colby"]
9
- s.date = %q{2009-06-10}
9
+ s.date = %q{2009-06-15}
10
10
  s.default_executable = %q{quarto}
11
11
  s.description = %q{Quarto is a Ruby framework for generating collections of documents from XML. It steps in where XSLT just won't cut it. Potential applications include web sites and e-books. It's built on top of ERB and REXML.}
12
12
  s.email = %q{jarrett@uchicago.edu}
@@ -24,14 +24,16 @@ Gem::Specification.new do |s|
24
24
  "lib/quarto/config.rb",
25
25
  "lib/quarto/element_wrapper.rb",
26
26
  "lib/quarto/generator.rb",
27
+ "lib/quarto/html_transformer.rb",
27
28
  "lib/quarto/inheritable_attributes.rb",
28
29
  "lib/quarto/init_project.rb",
29
30
  "lib/quarto/rails_helper.rb",
30
31
  "lib/quarto/rendering.rb",
32
+ "lib/quarto/transformation_helper.rb",
33
+ "lib/quarto/transformer.rb",
31
34
  "lib/quarto/url_helper.rb",
32
35
  "lib/quarto/xml_doc.rb",
33
- "quarto.gemspec",
34
- "test.rb"
36
+ "quarto.gemspec"
35
37
  ]
36
38
  s.has_rdoc = true
37
39
  s.homepage = %q{http://github.com/jarrett/quarto}
@@ -45,6 +47,7 @@ Gem::Specification.new do |s|
45
47
  "spec/generator_spec.rb",
46
48
  "spec/init_project_spec.rb",
47
49
  "spec/matchers/file_matchers.rb",
50
+ "spec/matchers/rexml_matchers.rb",
48
51
  "spec/rendering_spec.rb",
49
52
  "spec/sample_models.rb",
50
53
  "spec/sample_project/generate.rb",
@@ -55,6 +58,8 @@ Gem::Specification.new do |s|
55
58
  "spec/sample_project/models/product.rb",
56
59
  "spec/sample_project/urls.rb",
57
60
  "spec/spec_helper.rb",
61
+ "spec/transformation_helper_spec.rb",
62
+ "spec/transformer_spec.rb",
58
63
  "spec/url_helper_spec.rb"
59
64
  ]
60
65
 
@@ -63,11 +68,11 @@ Gem::Specification.new do |s|
63
68
  s.specification_version = 2
64
69
 
65
70
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
66
- s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
71
+ s.add_runtime_dependency(%q<activesupport>, ["~> 2.3.2"])
67
72
  else
68
- s.add_dependency(%q<activesupport>, [">= 2.3.2"])
73
+ s.add_dependency(%q<activesupport>, ["~> 2.3.2"])
69
74
  end
70
75
  else
71
- s.add_dependency(%q<activesupport>, [">= 2.3.2"])
76
+ s.add_dependency(%q<activesupport>, ["~> 2.3.2"])
72
77
  end
73
78
  end
@@ -7,7 +7,7 @@ describe Quarto::ElementWrapper::Base do
7
7
  @xml = Quarto.xml_doc
8
8
  end
9
9
 
10
- context 'wrapping an element with attributes' do
10
+ context 'wrapping an element with attributes and child elements' do
11
11
  before :each do
12
12
  @element = @xml.elements['companies/company']
13
13
  @company = Company.new(@element)
@@ -22,6 +22,11 @@ describe Quarto::ElementWrapper::Base do
22
22
  @company.name.should == '37Signals'
23
23
  end
24
24
 
25
+ it 'should return a REXML::Element if an elemement_attr contains markup' do
26
+ company = Company.find(:first, :xpath => "//company[name='Mega-lo-Mart']")
27
+ company.description.should be_a(REXML::Element)
28
+ end
29
+
25
30
  it 'should define methods from XML attributes by default' do
26
31
  @company.should respond_to(:reality)
27
32
  @company.reality.should == 'real'
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
  require 'fileutils'
3
3
 
4
4
  describe Quarto do
5
- include FileMatchers
5
+ include Quarto::FileMatchers
6
6
 
7
7
  context '.init_project on an empty directory' do
8
8
  before :all do
@@ -1,20 +1,22 @@
1
- module FileMatchers
2
- class ExistOnDisk
3
- def matches?(target)
4
- @target = File.expand_path(target)
5
- File.exists?(@target)
1
+ module Quarto
2
+ module FileMatchers
3
+ class ExistOnDisk
4
+ def matches?(target)
5
+ @target = File.expand_path(target)
6
+ File.exists?(@target)
7
+ end
8
+
9
+ def failure_message
10
+ "Expected file #{@target} to exist"
11
+ end
12
+
13
+ def negative_failure_message
14
+ "Expected file #{@target} not to exist"
15
+ end
6
16
  end
7
17
 
8
- def failure_message
9
- "Expected file #{@target} to exist"
18
+ def exist_on_disk
19
+ ExistOnDisk.new
10
20
  end
11
-
12
- def negative_failure_message
13
- "Expected file #{@target} not to exist"
14
- end
15
- end
16
-
17
- def exist_on_disk
18
- ExistOnDisk.new
19
21
  end
20
22
  end
@@ -0,0 +1,65 @@
1
+ module Quarto
2
+ module REXMLMatchers
3
+ class HaveElement
4
+ def initialize(element_name, options)
5
+ @element_name = element_name
6
+ @options = options
7
+ end
8
+
9
+ def matches?(target)
10
+ @target = target
11
+ !@target.find_first_recursive { |node| node_matches?(node) }.nil?
12
+ end
13
+
14
+ def failure_message
15
+ "Expected element '#{element_desc}' to be in:\n\n#{@target.to_s}"
16
+ end
17
+
18
+ def negative_failure_message
19
+ "Expected element '#{element_desc}' not to be in:\n\n#{@target.to_s}"
20
+ end
21
+
22
+ protected
23
+
24
+ def element_desc
25
+ desc = @element_name
26
+ if @options.has_key?(:attributes)
27
+ desc << " with attributes: #{@options[:attributes].inspect}"
28
+ if @options.has_key?(:text)
29
+ desc << " and text: '#{@options[:text]}'"
30
+ end
31
+ else
32
+ if @options.has_key?(:text)
33
+ desc << " with text: '#{@options[:text]}'"
34
+ end
35
+ end
36
+ desc
37
+ end
38
+
39
+ def node_matches?(node)
40
+ if node.name != @element_name
41
+ return false
42
+ end
43
+ if @options.has_key?(:attributes) and rexml_attrs_to_hash(node.attributes) != @options[:attributes]
44
+ return false
45
+ end
46
+ if @options.has_key?(:text) and node.text != @options[:text]
47
+ return false
48
+ end
49
+ true
50
+ end
51
+
52
+ def rexml_attrs_to_hash(rexml_attrs)
53
+ hash = {}
54
+ rexml_attrs.each do |attr_name, value|
55
+ hash[attr_name] = value
56
+ end
57
+ hash
58
+ end
59
+ end
60
+
61
+ def have_element(element_name, options = {})
62
+ HaveElement.new(element_name, options)
63
+ end
64
+ end
65
+ end
@@ -1,5 +1,5 @@
1
1
  class Company < Quarto::ElementWrapper::Base
2
- element_attrs :name, :industry
2
+ element_attrs :name, :industry, :description
3
3
 
4
4
  children :employees
5
5
 
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Quarto::TransformationHelper do
4
+ include Quarto::TransformationHelper
5
+
6
+ context '#tranform_xml' do
7
+ before :each do
8
+ @html = REXML::Document.new(%Q(
9
+ <div>
10
+ <p>Foo</p>
11
+ <p><a href="http://example.com">Bar</a></p>
12
+ </div>
13
+ ))
14
+ end
15
+
16
+ it 'should return a string' do
17
+ transform_xml(@html).should be_a(String)
18
+ transform_xml(@html.root).should be_a(String)
19
+ end
20
+
21
+ it 'should raise if passed anything other than a REXML::Element' do
22
+ lambda { transform_xml(nil) }.should raise_error(ArgumentError, 'Expected REXML::Element but got nil')
23
+ lambda { transform_xml('foo') }.should raise_error(ArgumentError, 'Expected REXML::Element but got "foo"')
24
+ end
25
+
26
+ context 'without transformer_class given' do
27
+ it 'should use HtmlTransformer' do
28
+ t = Quarto::HtmlTransformer.new
29
+ Quarto::HtmlTransformer.should_receive(:new).and_return(t)
30
+ transform_xml(@html)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,148 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe Quarto::Transformer do
4
+ include Quarto::REXMLMatchers
5
+
6
+ context '#transform' do
7
+ before :each do
8
+ @xml = %q(
9
+ <doc>
10
+ <div>
11
+ <p>Foo</p>
12
+ <p>Bar</p>
13
+
14
+ <book>
15
+ <title>Foobar</title>
16
+ <author>Baz</author>
17
+ <cover_url>http://example.com/foobar.jpeg</cover_url>
18
+ </book>
19
+ </div>
20
+ </doc>
21
+ )
22
+ @doc = REXML::Document.new(@xml)
23
+
24
+ class TestTransformer < Quarto::Transformer
25
+ def literal?(element)
26
+ ['doc', 'div', 'p'].include?(element.name)
27
+ end
28
+ end
29
+
30
+ @t = TestTransformer.new
31
+ end
32
+
33
+ after :each do
34
+ Object.class_eval do
35
+ remove_const :TestTransformer
36
+ end
37
+ end
38
+
39
+ it 'should return a string' do
40
+ @t.transform(@doc).should be_a(String)
41
+ @t.transform(@doc.root).should be_a(String)
42
+ @t.transform(REXML::Document.new('')).should be_a(String)
43
+ end
44
+
45
+ it 'should raise if passed anything other than a REXML::Element' do
46
+ lambda { @t.transform(nil) }.should raise_error(ArgumentError, 'Expected REXML::Element but got nil')
47
+ lambda { @t.transform('foo') }.should raise_error(ArgumentError, 'Expected REXML::Element but got "foo"')
48
+ end
49
+
50
+ it 'should not transform elements that lack custom transform methods and for which literal? returns true' do
51
+ result = REXML::Document.new(@t.transform(@doc))
52
+ result.should have_element('doc')
53
+ result.should have_element('div')
54
+ result.should have_element('p', :text => 'Foo')
55
+ result.should have_element('p', :text => 'Bar')
56
+ end
57
+
58
+ it 'should ignore elements that lack custom transform methods and for which literal? returns false' do
59
+ result = REXML::Document.new(@t.transform(@doc))
60
+ ['book', 'title', 'author' 'cover_url'].each do |el|
61
+ result.should_not have_element(el)
62
+ end
63
+ end
64
+
65
+ it 'should use custom transform methods' do
66
+ begin
67
+ class CustomizedTestTransformer < TestTransformer
68
+ def transform_book(book_element, raise_on_unrecognized_element)
69
+ %Q(
70
+ <div class="book">
71
+ <h1 class="title">#{book_element.elements['title'].text}</h1>
72
+ <h2 class="author">#{book_element.elements['author'].text}</h2>
73
+ <img src="#{book_element.elements['cover_url'].text}"/>
74
+ </div>
75
+ )
76
+ end
77
+ end
78
+
79
+ t = CustomizedTestTransformer.new
80
+ result = REXML::Document.new(t.transform(@doc))
81
+ result.should have_element('div', :attributes => {'class' => 'book'})
82
+ result.should have_element('h1', :attributes => {'class' => 'title'}, :text => 'Foobar')
83
+ result.should have_element('h2', :attributes => {'class' => 'author'}, :text => 'Baz')
84
+ result.should have_element('img', :attributes => {'src' => 'http://example.com/foobar.jpeg'})
85
+ ensure
86
+ Object.class_eval do
87
+ remove_const :CustomizedTestTransformer
88
+ end
89
+ end
90
+ end
91
+
92
+ it 'should give precedence to custom transform methods over literal?' do
93
+ begin
94
+ class CustomizedTestTransformer < TestTransformer
95
+ def transform_p(p_element, raise_on_unrecognized_element)
96
+ %Q(<div class="paragraph">#{p_element.text}</div>)
97
+ end
98
+ end
99
+
100
+ t = CustomizedTestTransformer.new
101
+ result = REXML::Document.new(t.transform(@doc))
102
+ result.should have_element('div', :attributes => {'class' => 'paragraph'}, :text => 'Foo')
103
+ result.should have_element('div', :attributes => {'class' => 'paragraph'}, :text => 'Bar')
104
+ ensure
105
+ Object.class_eval do
106
+ remove_const :CustomizedTestTransformer
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ context '.literals' do
113
+ before :each do
114
+ class TestTransformer < Quarto::Transformer
115
+ literals :doc, :div, 'p'
116
+ end
117
+ end
118
+
119
+ after :each do
120
+ Object.class_eval do
121
+ remove_const :TestTransformer
122
+ end
123
+ end
124
+
125
+ it 'should define literal? so that it returns true for any element on the list and false for any other' do
126
+ t = TestTransformer.new
127
+ ['doc', 'div', 'p'].each do |el_name|
128
+ t.send(:literal?, REXML::Element.new(el_name)).should == true
129
+ end
130
+ ['foo', 'bar', 'baz'].each do |el_name|
131
+ t.send(:literal?, REXML::Element.new(el_name)).should == false
132
+ end
133
+ end
134
+
135
+ it 'should have no effect if literal? is subsequently defined' do
136
+ class TestTransformer < Quarto::Transformer
137
+ def literal?(element)
138
+ false
139
+ end
140
+ end
141
+
142
+ t = TestTransformer.new
143
+ ['doc', 'div', 'p'].each do |el_name|
144
+ t.send(:literal?, REXML::Element.new(el_name)).should == false
145
+ end
146
+ end
147
+ end
148
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jarrett-quarto
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jarrett Colby
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-06-10 00:00:00 -07:00
12
+ date: 2009-06-15 00:00:00 -07:00
13
13
  default_executable: quarto
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -18,7 +18,7 @@ dependencies:
18
18
  version_requirement:
19
19
  version_requirements: !ruby/object:Gem::Requirement
20
20
  requirements:
21
- - - ">="
21
+ - - ~>
22
22
  - !ruby/object:Gem::Version
23
23
  version: 2.3.2
24
24
  version:
@@ -40,14 +40,16 @@ files:
40
40
  - lib/quarto/config.rb
41
41
  - lib/quarto/element_wrapper.rb
42
42
  - lib/quarto/generator.rb
43
+ - lib/quarto/html_transformer.rb
43
44
  - lib/quarto/inheritable_attributes.rb
44
45
  - lib/quarto/init_project.rb
45
46
  - lib/quarto/rails_helper.rb
46
47
  - lib/quarto/rendering.rb
48
+ - lib/quarto/transformation_helper.rb
49
+ - lib/quarto/transformer.rb
47
50
  - lib/quarto/url_helper.rb
48
51
  - lib/quarto/xml_doc.rb
49
52
  - quarto.gemspec
50
- - test.rb
51
53
  has_rdoc: true
52
54
  homepage: http://github.com/jarrett/quarto
53
55
  post_install_message:
@@ -80,6 +82,7 @@ test_files:
80
82
  - spec/generator_spec.rb
81
83
  - spec/init_project_spec.rb
82
84
  - spec/matchers/file_matchers.rb
85
+ - spec/matchers/rexml_matchers.rb
83
86
  - spec/rendering_spec.rb
84
87
  - spec/sample_models.rb
85
88
  - spec/sample_project/generate.rb
@@ -90,4 +93,6 @@ test_files:
90
93
  - spec/sample_project/models/product.rb
91
94
  - spec/sample_project/urls.rb
92
95
  - spec/spec_helper.rb
96
+ - spec/transformation_helper_spec.rb
97
+ - spec/transformer_spec.rb
93
98
  - spec/url_helper_spec.rb
data/test.rb DELETED
@@ -1,20 +0,0 @@
1
- require 'erb'
2
-
3
- module Foo
4
- def foo
5
- 6
6
- end
7
- end
8
-
9
- template = ERB.new %q(
10
- The value of x is <%= x %>
11
- The method foo returns <%= foo %>
12
- )
13
- x = 42
14
-
15
- b = binding
16
-
17
- eval 'include Foo', b
18
-
19
- template.extend(Foo)
20
- puts template.result(b)