pdf-labels 1.0.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/History.txt +8 -0
- data/LICENCE +38 -0
- data/Manifest.txt +141 -0
- data/README.txt +72 -0
- data/Rakefile +30 -0
- data/lib/alias.rb +8 -0
- data/lib/glabel_template.rb +36 -0
- data/lib/label.rb +52 -0
- data/lib/layout.rb +13 -0
- data/lib/length_node.rb +47 -0
- data/lib/markup.rb +25 -0
- data/lib/pdf_label_page.rb +171 -0
- data/lib/pdf_labels.rb +6 -0
- data/lib/template.rb +37 -0
- data/templates/avery-iso-templates.xml +222 -0
- data/templates/avery-other-templates.xml +21 -0
- data/templates/avery-us-templates.xml +599 -0
- data/templates/glabels-2.0.dtd +329 -0
- data/templates/misc-iso-templates.xml +434 -0
- data/templates/misc-other-templates.xml +21 -0
- data/templates/misc-us-templates.xml +183 -0
- data/templates/paper-sizes.xml +37 -0
- data/templates/zweckform-iso-templates.xml +197 -0
- data/test/test_pdf_label_page.rb +91 -0
- data/vendor/color.rb +87 -0
- data/vendor/color/cmyk.rb +182 -0
- data/vendor/color/css.rb +27 -0
- data/vendor/color/grayscale.rb +135 -0
- data/vendor/color/hsl.rb +130 -0
- data/vendor/color/palette.rb +15 -0
- data/vendor/color/palette/gimp.rb +107 -0
- data/vendor/color/palette/monocontrast.rb +180 -0
- data/vendor/color/rgb-colors.rb +189 -0
- data/vendor/color/rgb.rb +311 -0
- data/vendor/color/rgb/metallic.rb +28 -0
- data/vendor/color/yiq.rb +78 -0
- data/vendor/pdf/charts.rb +13 -0
- data/vendor/pdf/charts/stddev.rb +433 -0
- data/vendor/pdf/grid.rb +135 -0
- data/vendor/pdf/math.rb +108 -0
- data/vendor/pdf/pagenumbers.rb +288 -0
- data/vendor/pdf/quickref.rb +331 -0
- data/vendor/pdf/simpletable.rb +947 -0
- data/vendor/pdf/techbook.rb +901 -0
- data/vendor/pdf/writer.rb +2801 -0
- data/vendor/pdf/writer/arc4.rb +63 -0
- data/vendor/pdf/writer/fontmetrics.rb +202 -0
- data/vendor/pdf/writer/fonts/Courier-Bold.afm +342 -0
- data/vendor/pdf/writer/fonts/Courier-BoldOblique.afm +342 -0
- data/vendor/pdf/writer/fonts/Courier-Oblique.afm +342 -0
- data/vendor/pdf/writer/fonts/Courier.afm +342 -0
- data/vendor/pdf/writer/fonts/Helvetica-Bold.afm +2827 -0
- data/vendor/pdf/writer/fonts/Helvetica-BoldOblique.afm +2827 -0
- data/vendor/pdf/writer/fonts/Helvetica-Oblique.afm +3051 -0
- data/vendor/pdf/writer/fonts/Helvetica.afm +3051 -0
- data/vendor/pdf/writer/fonts/Symbol.afm +213 -0
- data/vendor/pdf/writer/fonts/Times-Bold.afm +2588 -0
- data/vendor/pdf/writer/fonts/Times-BoldItalic.afm +2384 -0
- data/vendor/pdf/writer/fonts/Times-Italic.afm +2667 -0
- data/vendor/pdf/writer/fonts/Times-Roman.afm +2419 -0
- data/vendor/pdf/writer/fonts/ZapfDingbats.afm +225 -0
- data/vendor/pdf/writer/graphics.rb +813 -0
- data/vendor/pdf/writer/graphics/imageinfo.rb +365 -0
- data/vendor/pdf/writer/lang.rb +44 -0
- data/vendor/pdf/writer/lang/en.rb +104 -0
- data/vendor/pdf/writer/object.rb +23 -0
- data/vendor/pdf/writer/object/action.rb +40 -0
- data/vendor/pdf/writer/object/annotation.rb +42 -0
- data/vendor/pdf/writer/object/catalog.rb +39 -0
- data/vendor/pdf/writer/object/contents.rb +69 -0
- data/vendor/pdf/writer/object/destination.rb +40 -0
- data/vendor/pdf/writer/object/encryption.rb +53 -0
- data/vendor/pdf/writer/object/font.rb +68 -0
- data/vendor/pdf/writer/object/fontdescriptor.rb +34 -0
- data/vendor/pdf/writer/object/fontencoding.rb +40 -0
- data/vendor/pdf/writer/object/image.rb +308 -0
- data/vendor/pdf/writer/object/info.rb +79 -0
- data/vendor/pdf/writer/object/outline.rb +30 -0
- data/vendor/pdf/writer/object/outlines.rb +30 -0
- data/vendor/pdf/writer/object/page.rb +195 -0
- data/vendor/pdf/writer/object/pages.rb +115 -0
- data/vendor/pdf/writer/object/procset.rb +46 -0
- data/vendor/pdf/writer/object/viewerpreferences.rb +74 -0
- data/vendor/pdf/writer/ohash.rb +58 -0
- data/vendor/pdf/writer/oreader.rb +25 -0
- data/vendor/pdf/writer/state.rb +48 -0
- data/vendor/pdf/writer/strokestyle.rb +140 -0
- data/vendor/transaction/simple.rb +693 -0
- data/vendor/transaction/simple/group.rb +133 -0
- data/vendor/transaction/simple/threadsafe.rb +52 -0
- data/vendor/transaction/simple/threadsafe/group.rb +23 -0
- data/vendor/xml-mapping/ChangeLog +128 -0
- data/vendor/xml-mapping/LICENSE +56 -0
- data/vendor/xml-mapping/README +386 -0
- data/vendor/xml-mapping/README_XPATH +175 -0
- data/vendor/xml-mapping/Rakefile +214 -0
- data/vendor/xml-mapping/TODO.txt +32 -0
- data/vendor/xml-mapping/doc/xpath_impl_notes.txt +119 -0
- data/vendor/xml-mapping/examples/company.rb +34 -0
- data/vendor/xml-mapping/examples/company.xml +26 -0
- data/vendor/xml-mapping/examples/company_usage.intin.rb +19 -0
- data/vendor/xml-mapping/examples/company_usage.intout +39 -0
- data/vendor/xml-mapping/examples/order.rb +61 -0
- data/vendor/xml-mapping/examples/order.xml +54 -0
- data/vendor/xml-mapping/examples/order_signature_enhanced.rb +7 -0
- data/vendor/xml-mapping/examples/order_signature_enhanced.xml +9 -0
- data/vendor/xml-mapping/examples/order_signature_enhanced_usage.intin.rb +12 -0
- data/vendor/xml-mapping/examples/order_signature_enhanced_usage.intout +16 -0
- data/vendor/xml-mapping/examples/order_usage.intin.rb +73 -0
- data/vendor/xml-mapping/examples/order_usage.intout +147 -0
- data/vendor/xml-mapping/examples/time_augm.intin.rb +19 -0
- data/vendor/xml-mapping/examples/time_augm.intout +23 -0
- data/vendor/xml-mapping/examples/time_node.rb +27 -0
- data/vendor/xml-mapping/examples/xpath_create_new.intin.rb +85 -0
- data/vendor/xml-mapping/examples/xpath_create_new.intout +181 -0
- data/vendor/xml-mapping/examples/xpath_docvsroot.intin.rb +30 -0
- data/vendor/xml-mapping/examples/xpath_docvsroot.intout +34 -0
- data/vendor/xml-mapping/examples/xpath_ensure_created.intin.rb +62 -0
- data/vendor/xml-mapping/examples/xpath_ensure_created.intout +114 -0
- data/vendor/xml-mapping/examples/xpath_pathological.intin.rb +42 -0
- data/vendor/xml-mapping/examples/xpath_pathological.intout +56 -0
- data/vendor/xml-mapping/examples/xpath_usage.intin.rb +51 -0
- data/vendor/xml-mapping/examples/xpath_usage.intout +57 -0
- data/vendor/xml-mapping/install.rb +40 -0
- data/vendor/xml-mapping/lib/xml/mapping.rb +14 -0
- data/vendor/xml-mapping/lib/xml/mapping/base.rb +571 -0
- data/vendor/xml-mapping/lib/xml/mapping/standard_nodes.rb +343 -0
- data/vendor/xml-mapping/lib/xml/mapping/version.rb +8 -0
- data/vendor/xml-mapping/lib/xml/xxpath.rb +354 -0
- data/vendor/xml-mapping/test/all_tests.rb +6 -0
- data/vendor/xml-mapping/test/company.rb +56 -0
- data/vendor/xml-mapping/test/documents_folders.rb +33 -0
- data/vendor/xml-mapping/test/fixtures/bookmarks1.xml +24 -0
- data/vendor/xml-mapping/test/fixtures/company1.xml +85 -0
- data/vendor/xml-mapping/test/fixtures/documents_folders.xml +71 -0
- data/vendor/xml-mapping/test/fixtures/documents_folders2.xml +30 -0
- data/vendor/xml-mapping/test/multiple_mappings.rb +80 -0
- data/vendor/xml-mapping/test/tests_init.rb +2 -0
- data/vendor/xml-mapping/test/xml_mapping_adv_test.rb +84 -0
- data/vendor/xml-mapping/test/xml_mapping_test.rb +201 -0
- data/vendor/xml-mapping/test/xpath_test.rb +273 -0
- metadata +191 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
= XML-XXPATH
|
|
2
|
+
|
|
3
|
+
== Overview, Motivation
|
|
4
|
+
|
|
5
|
+
Xml-xxpath is an (incomplete) XPath interpreter that is at the moment
|
|
6
|
+
bundled with xml-mapping. It is built on top of REXML. xml-mapping
|
|
7
|
+
uses xml-xxpath extensively for implementing its node types -- see the
|
|
8
|
+
README file and the reference documentation (and the source code) for
|
|
9
|
+
details. xml-xxpath, however, does not depend on xml-mapping at all,
|
|
10
|
+
and is useful in its own right -- maybe I'll later distribute it as a
|
|
11
|
+
seperate library instead of bundling it. xml-xxpath's XPath support is
|
|
12
|
+
vastly incomplete (see below), but, in addition to the normal
|
|
13
|
+
reading/matching functionality found in other XPath implementations
|
|
14
|
+
(i.e. "find all elements in a given XML document matching a given
|
|
15
|
+
XPath expression"), xml-xxpath supports <i>write access</i>. For
|
|
16
|
+
example, when writing the XPath expression
|
|
17
|
+
"/foo/bar[3]/baz[@key='hiho']" to the XML document
|
|
18
|
+
|
|
19
|
+
<foo>
|
|
20
|
+
<bar>
|
|
21
|
+
<baz key='ab'>hello</baz>
|
|
22
|
+
<baz key='xy'>goodbye</baz>
|
|
23
|
+
</bar>
|
|
24
|
+
</foo>
|
|
25
|
+
|
|
26
|
+
, you'll get:
|
|
27
|
+
|
|
28
|
+
<foo>
|
|
29
|
+
<bar>
|
|
30
|
+
<baz key='ab'>hello</baz>
|
|
31
|
+
<baz key='xy'>goodbye</baz>
|
|
32
|
+
</bar>
|
|
33
|
+
<bar/>
|
|
34
|
+
<bar><baz key='hiho'/></bar>
|
|
35
|
+
</foo>
|
|
36
|
+
|
|
37
|
+
This feature is used by xml-mapping when writing (marshalling) Ruby
|
|
38
|
+
objects to XML, and is actually the reason why I couldn't just use any
|
|
39
|
+
of the existing XPath implementations, e.g. the one that comes with
|
|
40
|
+
REXML. Also, the whole xml-xxpath implementation is just 300 lines of
|
|
41
|
+
Ruby code, it is quite fast (paths are precompiled), and xml-xxpath
|
|
42
|
+
returns matched elements in the order they appeared in the source
|
|
43
|
+
document -- I've heard REXML::XXPath doesn't do that :)
|
|
44
|
+
|
|
45
|
+
Some basic knowledge of XPath is helpful for reading this document (I
|
|
46
|
+
don't know very much either).
|
|
47
|
+
|
|
48
|
+
At the moment, xml-xxpath understands XPath expressions of the form
|
|
49
|
+
[<tt>/</tt>]_pathelement_<tt>/</tt>_pathelement_<tt>/</tt>..., where
|
|
50
|
+
each _pathelement_ must be one of these:
|
|
51
|
+
|
|
52
|
+
- a simple element name _name_, e.g. +signature+
|
|
53
|
+
|
|
54
|
+
- an attribute name, @_attr_name_, e.g. <tt>@key</tt>
|
|
55
|
+
|
|
56
|
+
- a combination of an element name and an attribute name and
|
|
57
|
+
-value, in the form _elt_name_[@_attr_name_='_attr_value_']
|
|
58
|
+
|
|
59
|
+
- an element name and an index, _elt_name_[_index_]
|
|
60
|
+
|
|
61
|
+
- the "match-all" path element, <tt>*</tt>
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
== Usage
|
|
65
|
+
|
|
66
|
+
Xml-xxpath defines the class XML::XXPath. An instance of that class
|
|
67
|
+
wraps an XPath expression, the string representation of which must be
|
|
68
|
+
supplied when constructing the instance. You then call instance
|
|
69
|
+
methods like _first_, _all_ or <i>create_new</i> on the instance,
|
|
70
|
+
supplying the REXML Element the XPath expression should be applied to,
|
|
71
|
+
and get the results, or, in the case of write access, the element is
|
|
72
|
+
updated in-place.
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
=== Read Access
|
|
76
|
+
|
|
77
|
+
:include: xpath_usage.intout
|
|
78
|
+
|
|
79
|
+
The objects supplied to the <tt>all()</tt>, <tt>first()</tt>, and
|
|
80
|
+
<tt>each()</tt> calls must be REXML element nodes, i.e. they must
|
|
81
|
+
support messages like <tt>elements</tt>, <tt>attributes</tt> etc
|
|
82
|
+
(instances of REXML::Element and its subclasses do this). The calls
|
|
83
|
+
return the found elements as instances of REXML::Element or
|
|
84
|
+
XML::XXPath::Accessors::Attribute. The latter is a wrapper around
|
|
85
|
+
attribute nodes that is largely call-compatible to
|
|
86
|
+
REXML::Element. This is so you can write things like
|
|
87
|
+
<tt>path.each{|node|puts node.text}</tt> without having to
|
|
88
|
+
special-case anything even if the path matches attributes, not just
|
|
89
|
+
elements.
|
|
90
|
+
|
|
91
|
+
As you can see, you can re-use path objects, applying them to
|
|
92
|
+
different XML elements at will. You should do this because the XPath
|
|
93
|
+
pattern is stored inside the XPath object in a pre-compiled form,
|
|
94
|
+
which makes it more efficient.
|
|
95
|
+
|
|
96
|
+
The path elements of the XPath pattern are applied to the
|
|
97
|
+
<tt>.elements</tt> collection of the passed XML element and its
|
|
98
|
+
sub-elements, starting with the first one. This is shown by the
|
|
99
|
+
following code:
|
|
100
|
+
|
|
101
|
+
:include: xpath_docvsroot.intout
|
|
102
|
+
|
|
103
|
+
A REXML +Document+ object is a REXML +Element+ object whose +elements+
|
|
104
|
+
collection consists only of a single member -- the document's root
|
|
105
|
+
node. The first path element of the XPath -- "foo" in the example --
|
|
106
|
+
is matched against that. That is why the path "/bar" in the example
|
|
107
|
+
doesn't match anything when matched against the document +d+ itself.
|
|
108
|
+
|
|
109
|
+
An ordinary REXML +Element+ object that represents a node somewhere
|
|
110
|
+
inside an XML tree has an +elements+ collection that consists of all
|
|
111
|
+
the element's direct sub-elements. That is why XPath patterns matched
|
|
112
|
+
against the +firstelt+ element in the example *must not* start with
|
|
113
|
+
"/first" (unless there is a child node that is also named "first").
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
=== Write Access
|
|
117
|
+
|
|
118
|
+
You may pass a <tt>:ensure_created=>true</tt> option argument to
|
|
119
|
+
_path_.first(_elt_)/_path_.all(_elt_) calls to make sure that _path_
|
|
120
|
+
exists inside the passed XML element _elt_. If it existed before,
|
|
121
|
+
nothing changes, and the call behaves just as it would without the
|
|
122
|
+
option argument. If the path didn't exist before, the XML element is
|
|
123
|
+
modified such that
|
|
124
|
+
|
|
125
|
+
- the path exists afterwards
|
|
126
|
+
|
|
127
|
+
- all paths that existed before still exist afterwards
|
|
128
|
+
|
|
129
|
+
- the modification is as small as possible (i.e. as few elements as
|
|
130
|
+
possible are added, additional attributes are added to existing
|
|
131
|
+
elements if possible etc.)
|
|
132
|
+
|
|
133
|
+
The created resp. previously existing, matching elements are returned.
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
Examples:
|
|
137
|
+
|
|
138
|
+
:include: xpath_ensure_created.intout
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
Alternatively, you may pass a <tt>:create_new=>true</tt> option
|
|
142
|
+
argument or call <tt>create_new</tt> (_path_.create_new(_elt_) is
|
|
143
|
+
equivalent to _path_.first(_elt_,:create_new=>true)). In that case, a
|
|
144
|
+
new node in created in _elt_ for each path element of _path_ (or an
|
|
145
|
+
exception raised if that wasn't possible for any path element).
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
|
|
149
|
+
:include: xpath_create_new.intout
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
=== Pathological Cases
|
|
153
|
+
|
|
154
|
+
What is created when the Path "*" is to be created inside an empty XML
|
|
155
|
+
element? The name of the element to be created isn't known, but still
|
|
156
|
+
some element must be created. The answer is that xml-xxpath creates a
|
|
157
|
+
special "unspecified" element whose name must be set by the caller
|
|
158
|
+
afterwards:
|
|
159
|
+
|
|
160
|
+
:include: xpath_pathological.intout
|
|
161
|
+
|
|
162
|
+
The "newelt" object in the last example is an ordinary
|
|
163
|
+
REXML::Element. xml-xxpath mixes the "unspecified" attribute into that
|
|
164
|
+
class, as well as into the XML::XXPath::Accessors::Attribute class
|
|
165
|
+
mentioned above.
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
== Implentation notes
|
|
169
|
+
|
|
170
|
+
<tt>doc/xpath_impl_notes.txt</tt> contains some documentation on the
|
|
171
|
+
implementation of xml-xxpath.
|
|
172
|
+
|
|
173
|
+
== License
|
|
174
|
+
|
|
175
|
+
Ruby's.
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# -*- ruby -*-
|
|
2
|
+
# adapted from active_record's Rakefile
|
|
3
|
+
|
|
4
|
+
require 'rubygems'
|
|
5
|
+
require 'rake'
|
|
6
|
+
require 'rake/testtask'
|
|
7
|
+
require 'rake/rdoctask'
|
|
8
|
+
require 'rake/packagetask'
|
|
9
|
+
require 'rake/gempackagetask'
|
|
10
|
+
#require 'rake/contrib/rubyforgepublisher'
|
|
11
|
+
require 'rake/contrib/sshpublisher'
|
|
12
|
+
|
|
13
|
+
require File.dirname(__FILE__)+"/lib/xml/mapping/version"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# yeah -- it's just stupid that these are private
|
|
17
|
+
|
|
18
|
+
class Rake::RDocTask
|
|
19
|
+
public :rdoc_target
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Rake::PackageTask
|
|
23
|
+
public :tgz_file, :zip_file
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Rake::GemPackageTask
|
|
27
|
+
public :gem_file
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
FILES_RDOC_EXTRA=%w{README README_XPATH TODO.txt doc/xpath_impl_notes.txt}
|
|
32
|
+
FILES_RDOC_INCLUDES=%w{examples/company.xml
|
|
33
|
+
examples/company.rb
|
|
34
|
+
examples/company_usage.intout
|
|
35
|
+
examples/order_usage.intout
|
|
36
|
+
examples/time_augm.intout
|
|
37
|
+
examples/xpath_usage.intout
|
|
38
|
+
examples/xpath_ensure_created.intout
|
|
39
|
+
examples/xpath_create_new.intout
|
|
40
|
+
examples/xpath_pathological.intout
|
|
41
|
+
examples/xpath_docvsroot.intout
|
|
42
|
+
examples/order_signature_enhanced_usage.intout}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
desc "Default Task"
|
|
46
|
+
task :default => [ :test ]
|
|
47
|
+
|
|
48
|
+
Rake::TestTask.new(:test) { |t|
|
|
49
|
+
t.test_files = ["test/all_tests.rb"]
|
|
50
|
+
t.verbose = true
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
# runs tests only if sources have changed since last succesful run of
|
|
54
|
+
# tests
|
|
55
|
+
file "test_run" => FileList.new('lib/**/*.rb','test/**/*.rb') do
|
|
56
|
+
Task[:test].invoke
|
|
57
|
+
touch "test_run"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
Rake::RDocTask.new { |rdoc|
|
|
63
|
+
rdoc.rdoc_dir = 'doc/api'
|
|
64
|
+
rdoc.title = "XML::Mapping -- Simple, extensible Ruby-to-XML (and back) mapper"
|
|
65
|
+
rdoc.options << '--line-numbers --inline-source --accessor cattr_accessor=object --include examples'
|
|
66
|
+
rdoc.rdoc_files.include(*FILES_RDOC_EXTRA)
|
|
67
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
68
|
+
|
|
69
|
+
# additional file dependencies for the rdoc task
|
|
70
|
+
# this somewhat of a black art because RDocTask doesn't document the
|
|
71
|
+
# prerequisite of its rdoc task (<rdoc_dir>/index.html)
|
|
72
|
+
file rdoc.rdoc_target => FILES_RDOC_INCLUDES
|
|
73
|
+
file "#{rdoc.rdoc_dir}/index.html" => FileList.new("examples/**/*.rb")
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
#rule '.intout' => ['.intin.rb', *FileList.new("lib/**/*.rb")] do |task| # doesn't work -- see below
|
|
77
|
+
rule '.intout' => ['.intin.rb'] do |task|
|
|
78
|
+
this_file_re = Regexp.compile(Regexp.quote(__FILE__))
|
|
79
|
+
b = binding
|
|
80
|
+
visible=true; visible_retval=true; handle_exceptions=false
|
|
81
|
+
old_stdout = $stdout
|
|
82
|
+
old_wd = Dir.pwd
|
|
83
|
+
begin
|
|
84
|
+
File.open(task.name,"w") do |fout|
|
|
85
|
+
$stdout = fout
|
|
86
|
+
File.open(task.source,"r") do |fin|
|
|
87
|
+
Dir.chdir File.dirname(task.name)
|
|
88
|
+
fin.read.split("#<=\n").each do |snippet|
|
|
89
|
+
|
|
90
|
+
snippet.scan(/^#:(.*?):$/) do |(switch,)|
|
|
91
|
+
case switch
|
|
92
|
+
when "visible"
|
|
93
|
+
visible=true
|
|
94
|
+
when "invisible"
|
|
95
|
+
visible=false
|
|
96
|
+
when "visible_retval"
|
|
97
|
+
visible_retval=true
|
|
98
|
+
when "invisible_retval"
|
|
99
|
+
visible_retval=false
|
|
100
|
+
when "handle_exceptions"
|
|
101
|
+
handle_exceptions=true
|
|
102
|
+
when "no_exceptions"
|
|
103
|
+
handle_exceptions=false
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
snippet.gsub!(/^#:.*?:(?:\n|\z)/,'')
|
|
107
|
+
|
|
108
|
+
print "#{snippet}\n" if visible
|
|
109
|
+
exc_handled = false
|
|
110
|
+
value = begin
|
|
111
|
+
eval(snippet,b)
|
|
112
|
+
rescue Exception
|
|
113
|
+
raise unless handle_exceptions
|
|
114
|
+
exc_handled = true
|
|
115
|
+
if visible
|
|
116
|
+
print "#{$!.class}: #{$!}\n"
|
|
117
|
+
for m in $@
|
|
118
|
+
break if m=~this_file_re
|
|
119
|
+
print "\tfrom #{m}\n"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
if visible and visible_retval and not exc_handled
|
|
124
|
+
print "=> #{value.inspect}\n"
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
rescue Exception
|
|
130
|
+
$stdout = old_stdout
|
|
131
|
+
Dir.chdir old_wd
|
|
132
|
+
File.delete task.name
|
|
133
|
+
raise
|
|
134
|
+
ensure
|
|
135
|
+
$stdout = old_stdout
|
|
136
|
+
Dir.chdir old_wd
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
# have to add additional prerequisites manually because it appears
|
|
141
|
+
# that rules can only define a single prerequisite :-\
|
|
142
|
+
for f in %w{examples/company_usage
|
|
143
|
+
examples/order_usage
|
|
144
|
+
examples/order_signature_enhanced_usage
|
|
145
|
+
examples/time_augm
|
|
146
|
+
examples/xpath_usage
|
|
147
|
+
examples/xpath_ensure_created
|
|
148
|
+
examples/xpath_create_new
|
|
149
|
+
examples/xpath_pathological
|
|
150
|
+
examples/xpath_docvsroot} do
|
|
151
|
+
file "#{f}.intout" => ["#{f}.intin.rb", 'examples/company.xml']
|
|
152
|
+
file "#{f}.intout" => FileList.new("lib/**/*.rb")
|
|
153
|
+
file "#{f}.intout" => FileList.new("examples/**/*.rb")
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
spec = Gem::Specification.new do |s|
|
|
158
|
+
s.name = 'xml-mapping'
|
|
159
|
+
s.version = XML::Mapping::VERSION
|
|
160
|
+
s.platform = Gem::Platform::RUBY
|
|
161
|
+
s.summary =
|
|
162
|
+
"An easy to use, extensible library for mapping Ruby objects to XML and back. Includes an XPath interpreter."
|
|
163
|
+
|
|
164
|
+
# Rubygems' RDoc support is incomplete... Can't seem to find a way
|
|
165
|
+
# to set the start page, or a set of files that should be includable
|
|
166
|
+
# but not processed by rdoc directly
|
|
167
|
+
s.files += FILES_RDOC_EXTRA
|
|
168
|
+
s.files += Dir.glob("{lib,examples,test}/**/*").delete_if do |item|
|
|
169
|
+
item.include?("CVS") || item =~ /~$/
|
|
170
|
+
end
|
|
171
|
+
s.files += %w{LICENSE Rakefile ChangeLog install.rb}
|
|
172
|
+
s.extra_rdoc_files = FILES_RDOC_EXTRA
|
|
173
|
+
s.rdoc_options += %w{--include examples}
|
|
174
|
+
|
|
175
|
+
s.require_path = 'lib'
|
|
176
|
+
s.autorequire = 'xml/mapping'
|
|
177
|
+
|
|
178
|
+
# s.add_dependency 'rexml'
|
|
179
|
+
|
|
180
|
+
s.has_rdoc=true
|
|
181
|
+
|
|
182
|
+
s.test_file = 'test/all_tests.rb'
|
|
183
|
+
|
|
184
|
+
s.author = 'Olaf Klischat'
|
|
185
|
+
s.email = 'klischat@cs.tu-berlin.de'
|
|
186
|
+
s.homepage = "http://xml-mapping.rubyforge.org"
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
Rake::GemPackageTask.new(spec) do |p|
|
|
192
|
+
p.gem_spec = spec
|
|
193
|
+
p.need_tar = true
|
|
194
|
+
p.need_zip = true
|
|
195
|
+
|
|
196
|
+
# (indirectly) add :rdoc, :test as prerequisites to :package task
|
|
197
|
+
# created by GemPackageTask
|
|
198
|
+
file "#{p.package_dir}/#{p.tgz_file}" => [ "test_run", :rdoc ]
|
|
199
|
+
file "#{p.package_dir}/#{p.zip_file}" => [ "test_run", :rdoc ]
|
|
200
|
+
file "#{p.package_dir}/#{p.gem_file}" => [ "test_run", :rdoc ]
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# run "rake package" to generate tgz, zip, gem in pkg/
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
task :rfpub_rdoc => [:rdoc] do
|
|
210
|
+
p=Rake::SshDirPublisher.new('xml-mapping.rubyforge.org',
|
|
211
|
+
'/var/www/gforge-projects/xml-mapping/',
|
|
212
|
+
'doc/api')
|
|
213
|
+
p.upload
|
|
214
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
- XML::XXPath: generalize foo[@x='bar'] to foo[<any XPath
|
|
2
|
+
expression>='bar'] (unless create/create_new implementation proves
|
|
3
|
+
to be too difficult, but I don't think it will...)
|
|
4
|
+
|
|
5
|
+
- documentation:
|
|
6
|
+
|
|
7
|
+
- README:
|
|
8
|
+
|
|
9
|
+
- multi-attribute nodes
|
|
10
|
+
|
|
11
|
+
- XML::Mapping: Move @options hash functionality from
|
|
12
|
+
SingleAttributeNode to Node.
|
|
13
|
+
|
|
14
|
+
- XML::Mapping/default attribute values: Update documentation, digest
|
|
15
|
+
"nil" issues...
|
|
16
|
+
|
|
17
|
+
- add streaming input/output to XML::Mapping, i.e. SAX-based input in
|
|
18
|
+
addition to the current REXML/DOM - based one. Probably won't be
|
|
19
|
+
implementable for some more complicated XPaths -- raise meaningful
|
|
20
|
+
exceptions in those cases.
|
|
21
|
+
|
|
22
|
+
- XML::XXPath/XML::Mapping: add XML text nodes (the sub-node of an
|
|
23
|
+
element node that contains that element's text) first-class to
|
|
24
|
+
XML::XXPath. Use it for things like text_node :contents, "text()".
|
|
25
|
+
|
|
26
|
+
Along those lines: promote XPath node "unspecifiedness" from an
|
|
27
|
+
attribute to a REXML node object of "unspecified" class that's
|
|
28
|
+
turned into an attribute/element/text node when necessary
|
|
29
|
+
|
|
30
|
+
- (eventually, maybe) provide a "scaffolding" feature to automatically
|
|
31
|
+
turn a dtd/schema into a set of node type definitions or even a set
|
|
32
|
+
of mapping classes
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
=== latest design (12/2004)
|
|
2
|
+
|
|
3
|
+
At the lowest level, the "Accessors" sub-module contains reader and
|
|
4
|
+
creator functions that correspond to the various types of path
|
|
5
|
+
elements (_elt_name_, @_attr_name_,
|
|
6
|
+
_elt_name_[@_attr_name_='_attr_value_'] etc.) that xml-xxpath
|
|
7
|
+
supports. A reader function gets an array of nodes and the search
|
|
8
|
+
parameters corresponding to its path element type (e.g. _elt_name_,
|
|
9
|
+
_attr_name_, _attr_value_) and returns an array with all matching
|
|
10
|
+
direct sub-nodes of any of the supplied nodes. A creator function gets
|
|
11
|
+
one node and the search parameters and returns the created sub-node.
|
|
12
|
+
|
|
13
|
+
An XPath expression <tt><things1>/<things2>/.../<thingsx></tt> is
|
|
14
|
+
compiled into a bunch of nested closures, each of which is responsible
|
|
15
|
+
for a specific path element and calls the corresponding accessor
|
|
16
|
+
function:
|
|
17
|
+
|
|
18
|
+
- <tt>@creator_procs</tt> -- an array of "creator"
|
|
19
|
+
functions. <tt>@creator_procs[i]</tt> gets passed a base node (XML
|
|
20
|
+
element) and a create_new flag, and it creates the path
|
|
21
|
+
<tt><things[x-i+1]>/<things[x-i+2]>/.../<thingsx></tt> inside the
|
|
22
|
+
base node and returns the hindmost element created (i.e. the one
|
|
23
|
+
corresponding to <tt><thingsx></tt>).
|
|
24
|
+
|
|
25
|
+
- <tt>@reader_proc</tt> -- a "reader" function that gets passed an
|
|
26
|
+
array of nodes and returns an array of all nodes that matched the
|
|
27
|
+
path in any of the supplied nodes, or, if no match was found, throws
|
|
28
|
+
:not_found along with the last non-empty set of nodes that was
|
|
29
|
+
found, and the element of <tt>@creator_procs</tt> that could be used
|
|
30
|
+
to create the remaining part of the path.
|
|
31
|
+
|
|
32
|
+
The +all+ function is then trivially implemented on top of this:
|
|
33
|
+
|
|
34
|
+
def all(node,options={})
|
|
35
|
+
raise "options not a hash" unless Hash===options
|
|
36
|
+
if options[:create_new]
|
|
37
|
+
return [ @creator_procs[-1].call(node,true) ]
|
|
38
|
+
else
|
|
39
|
+
last_nodes,rest_creator = catch(:not_found) do
|
|
40
|
+
return @reader_proc.call([node])
|
|
41
|
+
end
|
|
42
|
+
if options[:ensure_created]
|
|
43
|
+
[ rest_creator.call(last_nodes[0],false) ]
|
|
44
|
+
else
|
|
45
|
+
[]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
...and +first+, <tt>create_new</tt> etc. are even more trivial
|
|
51
|
+
frontends to that.
|
|
52
|
+
|
|
53
|
+
The implementations of the <tt>@creator_procs</tt> look like this:
|
|
54
|
+
|
|
55
|
+
@creator_procs[0] =
|
|
56
|
+
proc{|node,create_new| node}
|
|
57
|
+
|
|
58
|
+
@creator_procs[1] =
|
|
59
|
+
proc {|node,create_new|
|
|
60
|
+
@creator_procs[0].call(Accessors.create_subnode_by_<thingsx>(node,create_new,<thingsx>),
|
|
61
|
+
create_new)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@creator_procs[2] =
|
|
65
|
+
proc {|node,create_new|
|
|
66
|
+
@creator_procs[1].call(Accessors.create_subnode_by_<thingsx-1>(node,create_new,<thingsx-1>),
|
|
67
|
+
create_new)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
@creator_procs[n] =
|
|
73
|
+
proc {|node,create_new|
|
|
74
|
+
@creator_procs[n-1].call(Accessors.create_subnode_by_<things[x+1-n]>(node,create_new,<things[x+1-n]>),
|
|
75
|
+
create_new)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
...
|
|
79
|
+
@creator_procs[x] =
|
|
80
|
+
proc {|node,create_new|
|
|
81
|
+
@creator_procs[x-1].call(Accessors.create_subnode_by_<things1>(node,create_new,<things1>),
|
|
82
|
+
create_new)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
..and the implementation of @reader_proc looks like this:
|
|
88
|
+
|
|
89
|
+
@reader_proc = rpx where
|
|
90
|
+
|
|
91
|
+
rp0 = proc {|nodes| nodes}
|
|
92
|
+
|
|
93
|
+
rp1 = proc {|nodes|
|
|
94
|
+
next_nodes = Accessors.subnodes_by_<thingsx>(nodes,<thingsx>)
|
|
95
|
+
if (next_nodes == [])
|
|
96
|
+
throw :not_found, [nodes,@creator_procs[1]]
|
|
97
|
+
else
|
|
98
|
+
rp0.call(next_nodes)
|
|
99
|
+
end
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
rp2 = proc {|nodes|
|
|
103
|
+
next_nodes = Accessors.subnodes_by_<thingsx-1>(nodes,<thingsx-1>)
|
|
104
|
+
if (next_nodes == [])
|
|
105
|
+
throw :not_found, [nodes,@creator_procs[2]]
|
|
106
|
+
else
|
|
107
|
+
rp1.call(next_nodes)
|
|
108
|
+
end
|
|
109
|
+
}
|
|
110
|
+
...
|
|
111
|
+
|
|
112
|
+
rpx = proc {|nodes|
|
|
113
|
+
next_nodes = Accessors.subnodes_by_<things1>(nodes,<things1>)
|
|
114
|
+
if (next_nodes == [])
|
|
115
|
+
throw :not_found, [nodes,@creator_procs[x]]
|
|
116
|
+
else
|
|
117
|
+
rpx-1.call(next_nodes)
|
|
118
|
+
end
|
|
119
|
+
}
|