om 0.1.10 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +27 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/om/samples/mods_article.rb +64 -0
- data/lib/om/samples.rb +2 -0
- data/lib/om/tree_node.rb +24 -0
- data/lib/om/xml/document.rb +68 -0
- data/lib/om/xml/named_term_proxy.rb +37 -0
- data/lib/om/xml/node_generator.rb +14 -0
- data/lib/om/xml/term.rb +223 -0
- data/lib/om/xml/term_value_operators.rb +182 -0
- data/lib/om/xml/term_xpath_generator.rb +224 -0
- data/lib/om/xml/terminology.rb +216 -0
- data/lib/om/xml/vocabulary.rb +17 -0
- data/lib/om/xml.rb +17 -0
- data/lib/om.rb +2 -0
- data/om.gemspec +37 -6
- data/spec/fixtures/mods_articles/hydrangea_article1.xml +0 -1
- data/spec/integration/rights_metadata_integration_example_spec.rb +27 -15
- data/spec/unit/document_spec.rb +141 -0
- data/spec/unit/generator_spec.rb +7 -1
- data/spec/unit/named_term_proxy_spec.rb +39 -0
- data/spec/unit/node_generator_spec.rb +27 -0
- data/spec/unit/properties_spec.rb +1 -1
- data/spec/unit/term_builder_spec.rb +195 -0
- data/spec/unit/term_spec.rb +180 -0
- data/spec/unit/term_value_operators_spec.rb +361 -0
- data/spec/unit/term_xpath_generator_spec.rb +111 -0
- data/spec/unit/terminology_builder_spec.rb +178 -0
- data/spec/unit/terminology_spec.rb +322 -0
- data/spec/unit/validation_spec.rb +4 -0
- metadata +40 -7
@@ -0,0 +1,224 @@
|
|
1
|
+
module OM::XML::TermXpathGenerator
|
2
|
+
|
3
|
+
def self.generate_relative_xpath(mapper)
|
4
|
+
template = ""
|
5
|
+
predicates = []
|
6
|
+
|
7
|
+
if mapper.namespace_prefix.nil?
|
8
|
+
complete_prefix = ""
|
9
|
+
else
|
10
|
+
complete_prefix = mapper.namespace_prefix + ":"
|
11
|
+
end
|
12
|
+
|
13
|
+
if mapper.path.kind_of?(Hash)
|
14
|
+
if mapper.path.has_key?(:attribute)
|
15
|
+
base_path = "@"+mapper.path[:attribute]
|
16
|
+
else
|
17
|
+
raise "#{mapper.path} is an invalid path for an OM::XML::Term. You should provide either a string or {:attributes=>XXX}"
|
18
|
+
end
|
19
|
+
else
|
20
|
+
unless mapper.namespace_prefix.nil?
|
21
|
+
template << complete_prefix
|
22
|
+
end
|
23
|
+
base_path = mapper.path
|
24
|
+
end
|
25
|
+
template << base_path
|
26
|
+
|
27
|
+
unless mapper.attributes.nil?
|
28
|
+
mapper.attributes.each_pair do |attr_name, attr_value|
|
29
|
+
predicates << "@#{attr_name}=\"#{attr_value}\""
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
unless predicates.empty?
|
34
|
+
template << "["+ delimited_list(predicates, " and ")+"]"
|
35
|
+
end
|
36
|
+
|
37
|
+
return template
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.generate_absolute_xpath(mapper)
|
41
|
+
relative = generate_relative_xpath(mapper)
|
42
|
+
if mapper.parent.nil?
|
43
|
+
return "//#{relative}"
|
44
|
+
else
|
45
|
+
return mapper.parent.xpath_absolute + "/" + relative
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.generate_constrained_xpath(mapper)
|
50
|
+
if mapper.namespace_prefix.nil?
|
51
|
+
complete_prefix = ""
|
52
|
+
else
|
53
|
+
complete_prefix = mapper.namespace_prefix + ":"
|
54
|
+
end
|
55
|
+
|
56
|
+
absolute = generate_absolute_xpath(mapper)
|
57
|
+
constraint_predicates = []
|
58
|
+
|
59
|
+
arguments_for_contains_function = []
|
60
|
+
|
61
|
+
if !mapper.default_content_path.nil?
|
62
|
+
arguments_for_contains_function << "#{complete_prefix}#{mapper.default_content_path}"
|
63
|
+
end
|
64
|
+
|
65
|
+
# If no subelements have been specified to search within, set contains function to search within the current node
|
66
|
+
if arguments_for_contains_function.empty?
|
67
|
+
arguments_for_contains_function << "."
|
68
|
+
end
|
69
|
+
|
70
|
+
arguments_for_contains_function << "\":::constraint_value:::\""
|
71
|
+
|
72
|
+
contains_function = "contains(#{delimited_list(arguments_for_contains_function)})"
|
73
|
+
|
74
|
+
template = add_predicate(absolute, contains_function)
|
75
|
+
return template.gsub( /:::(.*?):::/ ) { '#{'+$1+'}' }.gsub('"', '\"')
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.generate_xpath(mapper, type)
|
79
|
+
case type
|
80
|
+
when :relative
|
81
|
+
self.generate_relative_xpath(mapper)
|
82
|
+
when :absolute
|
83
|
+
self.generate_absolute_xpath(mapper)
|
84
|
+
when :constrained
|
85
|
+
self.generate_constrained_xpath(mapper)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Use the given +terminology+ to generate an xpath with (optional) node indexes for each of the term pointers.
|
90
|
+
# Ex. OM::XML::TermXpathGenerator.xpath_with_indexes(my_terminology, {:conference=>0}, {:role=>1}, :text )
|
91
|
+
# will yield an xpath similar to this: '//oxns:name[@type="conference"][1]/oxns:role[2]/oxns:roleTerm[@type="text"]'
|
92
|
+
def self.generate_xpath_with_indexes(terminology, *pointers)
|
93
|
+
if pointers.first.nil?
|
94
|
+
root_term = terminology.root_terms.first
|
95
|
+
if root_term.nil?
|
96
|
+
return "/"
|
97
|
+
else
|
98
|
+
return root_term.xpath
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
query_constraints = nil
|
103
|
+
|
104
|
+
if pointers.length > 1 && pointers.last.kind_of?(Hash)
|
105
|
+
query_constraints = pointers.pop
|
106
|
+
end
|
107
|
+
|
108
|
+
if pointers.length == 1 && pointers.first.instance_of?(String)
|
109
|
+
return xpath_query = pointers.first
|
110
|
+
end
|
111
|
+
|
112
|
+
# if pointers.first.kind_of?(String)
|
113
|
+
# return pointers.first
|
114
|
+
# end
|
115
|
+
|
116
|
+
keys = []
|
117
|
+
xpath = "//"
|
118
|
+
|
119
|
+
pointers = OM.destringify(pointers)
|
120
|
+
pointers.each_with_index do |pointer, pointer_index|
|
121
|
+
|
122
|
+
if pointer.kind_of?(Hash)
|
123
|
+
k = pointer.keys.first
|
124
|
+
index = pointer[k]
|
125
|
+
else
|
126
|
+
k = pointer
|
127
|
+
index = nil
|
128
|
+
end
|
129
|
+
|
130
|
+
keys << k
|
131
|
+
|
132
|
+
term = terminology.retrieve_term(*keys)
|
133
|
+
# Return nil if there is no term to work with
|
134
|
+
if term.nil? then return nil end
|
135
|
+
|
136
|
+
# If we've encountered a NamedTermProxy, insert path sections corresponding to
|
137
|
+
# terms corresponding to each entry in its proxy_pointer rather than just the final term that it points to.
|
138
|
+
if term.kind_of? OM::XML::NamedTermProxy
|
139
|
+
current_location = term.parent
|
140
|
+
relative_path = ""
|
141
|
+
term.proxy_pointer.each_with_index do |proxy_pointer, proxy_pointer_index|
|
142
|
+
proxy_term = current_location.retrieve_term(proxy_pointer)
|
143
|
+
proxy_relative_path = proxy_term.xpath_relative
|
144
|
+
if proxy_pointer_index > 0
|
145
|
+
proxy_relative_path = "/"+proxy_relative_path
|
146
|
+
end
|
147
|
+
relative_path << proxy_relative_path
|
148
|
+
current_location = proxy_term
|
149
|
+
end
|
150
|
+
else
|
151
|
+
relative_path = term.xpath_relative
|
152
|
+
|
153
|
+
unless index.nil?
|
154
|
+
relative_path = add_node_index_predicate(relative_path, index)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
if pointer_index > 0
|
159
|
+
relative_path = "/"+relative_path
|
160
|
+
end
|
161
|
+
xpath << relative_path
|
162
|
+
end
|
163
|
+
|
164
|
+
final_term = terminology.retrieve_term(*keys)
|
165
|
+
|
166
|
+
if query_constraints.kind_of?(Hash)
|
167
|
+
contains_functions = []
|
168
|
+
query_constraints.each_pair do |k,v|
|
169
|
+
if k.instance_of?(Symbol)
|
170
|
+
constraint_path = final_term.children[k].xpath_relative
|
171
|
+
else
|
172
|
+
constraint_path = k
|
173
|
+
end
|
174
|
+
contains_functions << "contains(#{constraint_path}, \"#{v}\")"
|
175
|
+
end
|
176
|
+
|
177
|
+
xpath = add_predicate(xpath, delimited_list(contains_functions, " and ") )
|
178
|
+
end
|
179
|
+
|
180
|
+
return xpath
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
def self.delimited_list( values_array, delimiter=", ")
|
185
|
+
result = values_array.collect{|a| a + delimiter}.to_s.chomp(delimiter)
|
186
|
+
end
|
187
|
+
|
188
|
+
# Adds xpath xpath node index predicate to the end of your xpath query
|
189
|
+
# Example:
|
190
|
+
# add_node_index_predicate("//oxns:titleInfo",0)
|
191
|
+
# => "//oxns:titleInfo[1]"
|
192
|
+
#
|
193
|
+
# add_node_index_predicate("//oxns:titleInfo[@lang=\"finnish\"]",0)
|
194
|
+
# => "//oxns:titleInfo[@lang=\"finnish\"][1]"
|
195
|
+
def self.add_node_index_predicate(xpath_query, array_index_value)
|
196
|
+
modified_query = xpath_query.dup
|
197
|
+
modified_query << "[#{array_index_value + 1}]"
|
198
|
+
end
|
199
|
+
|
200
|
+
# Adds xpath:position() method call to the end of your xpath query
|
201
|
+
# Examples:
|
202
|
+
#
|
203
|
+
# add_position_predicate("//oxns:titleInfo",0)
|
204
|
+
# => "//oxns:titleInfo[position()=1]"
|
205
|
+
#
|
206
|
+
# add_position_predicate("//oxns:titleInfo[@lang=\"finnish\"]",0)
|
207
|
+
# => "//oxns:titleInfo[@lang=\"finnish\" and position()=1]"
|
208
|
+
def self.add_position_predicate(xpath_query, array_index_value)
|
209
|
+
position_function = "position()=#{array_index_value + 1}"
|
210
|
+
self.add_predicate(xpath_query, position_function)
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.add_predicate(xpath_query, predicate)
|
214
|
+
modified_query = xpath_query.dup
|
215
|
+
# if xpath_query.include?("]")
|
216
|
+
if xpath_query[xpath_query.length-1..xpath_query.length] == "]"
|
217
|
+
modified_query.insert(xpath_query.rindex("]"), " and #{predicate}")
|
218
|
+
else
|
219
|
+
modified_query << "[#{predicate}]"
|
220
|
+
end
|
221
|
+
return modified_query
|
222
|
+
end
|
223
|
+
|
224
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
class OM::XML::Terminology
|
2
|
+
|
3
|
+
class BadPointerError < StandardError; end
|
4
|
+
class CircularReferenceError < StandardError; end
|
5
|
+
|
6
|
+
class Builder
|
7
|
+
|
8
|
+
attr_accessor :schema, :namespaces
|
9
|
+
attr_reader :term_builders
|
10
|
+
###
|
11
|
+
# Create a new Terminology Builder object. +options+ are sent to the top level
|
12
|
+
# Document that is being built.
|
13
|
+
# (not yet supported:) +root+ can be a point in an existing Terminology that you want to add Mappers into
|
14
|
+
#
|
15
|
+
# Building a document with a particular encoding for example:
|
16
|
+
#
|
17
|
+
# Nokogiri::XML::Builder.new(:encoding => 'UTF-8') do |xml|
|
18
|
+
# ...
|
19
|
+
# end
|
20
|
+
def initialize(options = {}, root = nil, &block)
|
21
|
+
@schema = options.fetch(:schema,nil)
|
22
|
+
@namespaces = options.fetch(:namespaces,{})
|
23
|
+
@term_builders = {}
|
24
|
+
@cur_term_builder = nil
|
25
|
+
|
26
|
+
yield self if block_given?
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set the root of the Terminology, along with namespace & schema info
|
30
|
+
def root opts, &block
|
31
|
+
@schema = opts.fetch(:schema,nil)
|
32
|
+
opts.select {|k,v| k.to_s.include?("xmlns")}.each do |ns_pair|
|
33
|
+
@namespaces[ns_pair.first.to_s] = ns_pair.last
|
34
|
+
if ns_pair.first.to_s == "xmlns"
|
35
|
+
@namespaces["oxns"] = ns_pair.last
|
36
|
+
end
|
37
|
+
end
|
38
|
+
root_term_builder = OM::XML::Term::Builder.new(opts.fetch(:path,:root).to_s.sub(/[_!]$/, '')).is_root_term(true)
|
39
|
+
@term_builders[root_term_builder.name] = root_term_builder
|
40
|
+
|
41
|
+
return root_term_builder
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns an array of Terms that have been marked as "root" terms
|
45
|
+
def root_term_builders
|
46
|
+
@term_builders.values.select {|term_builder| term_builder.settings[:is_root_term] == true }
|
47
|
+
end
|
48
|
+
|
49
|
+
def method_missing method, *args, &block # :nodoc:
|
50
|
+
parent_builder = @cur_term_builder
|
51
|
+
@cur_term_builder = OM::XML::Term::Builder.new(method.to_s.sub(/[_!]$/, ''), self)
|
52
|
+
|
53
|
+
# Attach to parent
|
54
|
+
if parent_builder
|
55
|
+
parent_builder.add_child @cur_term_builder
|
56
|
+
else
|
57
|
+
@term_builders [@cur_term_builder.name] = @cur_term_builder
|
58
|
+
end
|
59
|
+
|
60
|
+
# Apply options
|
61
|
+
opts = args.shift
|
62
|
+
@cur_term_builder.settings.merge!(opts) if opts
|
63
|
+
|
64
|
+
# Parse children
|
65
|
+
yield if block
|
66
|
+
|
67
|
+
@cur_term_builder = parent_builder
|
68
|
+
end
|
69
|
+
|
70
|
+
# Returns the TermBuilder corresponding to the given _pointer_.
|
71
|
+
def retrieve_term_builder(*args)
|
72
|
+
args_cp = args.dup
|
73
|
+
current_term = @term_builders[args_cp.delete_at(0)]
|
74
|
+
if current_term.nil?
|
75
|
+
raise OM::XML::Terminology::BadPointerError, "This TerminologyBuilder does not have a root TermBuilder defined that corresponds to \"#{args.first.inspect}\""
|
76
|
+
end
|
77
|
+
args_cp.each do |arg|
|
78
|
+
current_term = current_term.retrieve_child(arg)
|
79
|
+
if current_term.nil?
|
80
|
+
raise OM::XML::Terminology::BadPointerError, "You attempted to retrieve a TermBuilder using this pointer: #{args.inspect} but no TermBuilder exists at that location. Everything is fine until \"#{arg.inspect}\", which doesn't exist."
|
81
|
+
end
|
82
|
+
end
|
83
|
+
return current_term
|
84
|
+
end
|
85
|
+
|
86
|
+
def build
|
87
|
+
terminology = OM::XML::Terminology.new(:schema=>@schema, :namespaces=>@namespaces)
|
88
|
+
root_term_builders.each do |root_term_builder|
|
89
|
+
root_term_builder.children = self.term_builders.dup
|
90
|
+
root_term_builder.children.delete(root_term_builder.name)
|
91
|
+
end
|
92
|
+
@term_builders.each_value do |root_builder|
|
93
|
+
terminology.add_term root_builder.build
|
94
|
+
end
|
95
|
+
terminology
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Terminology Class Definition
|
100
|
+
|
101
|
+
attr_accessor :terms, :schema, :namespaces
|
102
|
+
|
103
|
+
def initialize(options={})
|
104
|
+
@schema = options.fetch(:schema,nil)
|
105
|
+
@namespaces = options.fetch(:namespaces,{})
|
106
|
+
@terms = {}
|
107
|
+
end
|
108
|
+
|
109
|
+
# Add a term to the root of the terminology
|
110
|
+
def add_term(term)
|
111
|
+
@terms[term.name.to_sym] = term
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns true if the current terminology has a term defined at the location indicated by +pointers+ array
|
115
|
+
def has_term?(*pointers)
|
116
|
+
begin
|
117
|
+
retrieve_term(*OM.pointers_to_flat_array(pointers, false))
|
118
|
+
return true
|
119
|
+
rescue
|
120
|
+
return false
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns the Term corresponding to the given _pointer_.
|
125
|
+
def retrieve_term(*args)
|
126
|
+
args_cp = args.dup
|
127
|
+
current_term = terms[args_cp.delete_at(0)]
|
128
|
+
if current_term.nil?
|
129
|
+
raise OM::XML::Terminology::BadPointerError, "This Terminology does not have a root term defined that corresponds to \"#{args.first.inspect}\""
|
130
|
+
else
|
131
|
+
args_cp.each do |arg|
|
132
|
+
current_term = current_term.retrieve_child(arg)
|
133
|
+
if current_term.nil?
|
134
|
+
raise OM::XML::Terminology::BadPointerError, "You attempted to retrieve a Term using this pointer: #{args.inspect} but no Term exists at that location. Everything is fine until \"#{arg.inspect}\", which doesn't exist."
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
return current_term
|
139
|
+
end
|
140
|
+
|
141
|
+
# Return the appropriate xpath query for retrieving nodes corresponding to the term identified by +pointers+.
|
142
|
+
# If the last argument is a String or a Hash, it will be used to add +constraints+ to the resulting xpath query.
|
143
|
+
def xpath_for(*pointers)
|
144
|
+
if pointers.length == 1 && pointers.first.instance_of?(String)
|
145
|
+
xpath_query = pointers.first
|
146
|
+
else
|
147
|
+
query_constraints = nil
|
148
|
+
|
149
|
+
if pointers.length > 1 && !pointers.last.kind_of?(Symbol)
|
150
|
+
query_constraints = pointers.pop
|
151
|
+
end
|
152
|
+
|
153
|
+
term = retrieve_term( *pointers )
|
154
|
+
|
155
|
+
if !term.nil?
|
156
|
+
if query_constraints.kind_of?(String)
|
157
|
+
constraint_value = query_constraints
|
158
|
+
xpath_template = term.xpath_constrained
|
159
|
+
xpath_query = eval( '"' + xpath_template + '"' )
|
160
|
+
elsif query_constraints.kind_of?(Hash) && !query_constraints.empty?
|
161
|
+
key_value_pair = query_constraints.first
|
162
|
+
constraint_value = key_value_pair.last
|
163
|
+
xpath_template = term.children[key_value_pair.first].xpath_constrained
|
164
|
+
xpath_query = eval( '"' + xpath_template + '"' )
|
165
|
+
else
|
166
|
+
xpath_query = term.xpath
|
167
|
+
end
|
168
|
+
else
|
169
|
+
xpath_query = nil
|
170
|
+
end
|
171
|
+
end
|
172
|
+
return xpath_query
|
173
|
+
end
|
174
|
+
|
175
|
+
# Use the current terminology to generate an xpath with (optional) node indexes for each of the term pointers.
|
176
|
+
# Ex. terminology.xpath_with_indexes({:conference=>0}, {:role=>1}, :text )
|
177
|
+
# will yield an xpath like this: '//oxns:name[@type="conference"][1]/oxns:role[2]/oxns:roleTerm[@type="text"]'
|
178
|
+
def xpath_with_indexes(*pointers)
|
179
|
+
OM::XML::TermXpathGenerator.generate_xpath_with_indexes(self, *pointers)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Retrieves a Term corresponding to +term_pointers+ and return the corresponding xml_builder_template for that term.
|
183
|
+
# The resulting xml_builder_template can be passed as a block into Nokogiri::XML::Builder.new
|
184
|
+
#
|
185
|
+
# +term_pointers+ point to the Term you want to generate a builder template for
|
186
|
+
# If the last term_pointer is a String or a Hash, it will be passed into the Term's xml_builder_template method as extra_opts
|
187
|
+
# see also: Term.xml_builder_template
|
188
|
+
def xml_builder_template(*term_pointers)
|
189
|
+
extra_opts = {}
|
190
|
+
|
191
|
+
if term_pointers.length > 1 && !term_pointers.last.kind_of?(Symbol)
|
192
|
+
extra_opts = term_pointers.pop
|
193
|
+
end
|
194
|
+
|
195
|
+
term = retrieve_term(*term_pointers)
|
196
|
+
return term.xml_builder_template(extra_opts)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Returns an array of Terms that have been marked as "root" terms
|
200
|
+
def root_terms
|
201
|
+
terms.values.select {|term| term.is_root_term? }
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.term_generic_name(*pointers)
|
205
|
+
pointers_to_flat_array(pointers, false).join("_")
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.term_hierarchical_name(*pointers)
|
209
|
+
pointers_to_flat_array(pointers, true).join("_")
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.pointers_to_flat_array(pointers, include_indices=true)
|
213
|
+
OM.pointers_to_flat_array(pointers, include_indices)
|
214
|
+
end
|
215
|
+
|
216
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class OM::XML::Vocabulary
|
2
|
+
|
3
|
+
attr_accessor :builder
|
4
|
+
# Vocabularies are not editable once they've been created because inserting/removing/rearranging mappers in a vocabulary
|
5
|
+
# will invalidate the xpath queries for an entire branch of the Vocabulary's tree of mappers.
|
6
|
+
# If you want to change a vocabulary's structure, retrieve it's +builder+, make your changes, and re-generate the vocabulary.
|
7
|
+
#
|
8
|
+
# Ex:
|
9
|
+
# builder = vocabulary.builder
|
10
|
+
# builder.insert_mapper(:name_, :namePart)
|
11
|
+
# vocabulary = builder.build
|
12
|
+
|
13
|
+
# Mappers can be retrieved by their mapper name
|
14
|
+
# Ex.
|
15
|
+
# vocabulary.retrieve_mapper(:name_, :namePart)
|
16
|
+
|
17
|
+
end
|
data/lib/om/xml.rb
CHANGED
@@ -5,10 +5,26 @@ require "om/xml/properties"
|
|
5
5
|
require "om/xml/property_value_operators"
|
6
6
|
require "om/xml/generator"
|
7
7
|
|
8
|
+
require "om/xml/terminology"
|
9
|
+
require "om/xml/term"
|
10
|
+
require "om/xml/term_xpath_generator"
|
11
|
+
require "om/xml/node_generator"
|
12
|
+
require "om/xml/term_value_operators"
|
13
|
+
require "om/xml/named_term_proxy"
|
14
|
+
require "om/xml/document"
|
15
|
+
|
16
|
+
|
8
17
|
module OM::XML
|
9
18
|
|
10
19
|
attr_accessor :ng_xml
|
11
20
|
|
21
|
+
# Module Methods -- These methods can be called directly on the Module itself
|
22
|
+
|
23
|
+
# Transforms an array of values into a string delimited by +delimiter+
|
24
|
+
def self.delimited_list( values_array, delimiter=", ")
|
25
|
+
result = values_array.collect{|a| a + delimiter}.to_s.chomp(delimiter)
|
26
|
+
end
|
27
|
+
|
12
28
|
# Class Methods -- These methods will be available on classes that include this Module
|
13
29
|
|
14
30
|
module ClassMethods
|
@@ -42,4 +58,5 @@ module OM::XML
|
|
42
58
|
klass.send(:include, OM::XML::Generator)
|
43
59
|
end
|
44
60
|
|
61
|
+
|
45
62
|
end
|
data/lib/om.rb
CHANGED
data/om.gemspec
CHANGED
@@ -5,16 +5,17 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{om}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "1.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Matt Zumwalt"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-09-15}
|
13
13
|
s.description = %q{OM (Opinionated Metadata): A library to help you tame sprawling XML schemas like MODS. Wraps Nokogiri documents in objects with miscellaneous helper methods for doing things like retrieve generated xpath queries or look up properties based on a simplified DSL}
|
14
14
|
s.email = %q{matt.zumwalt@yourmediashelf.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
"README.rdoc"
|
17
|
+
"README.rdoc",
|
18
|
+
"README.textile"
|
18
19
|
]
|
19
20
|
s.files = [
|
20
21
|
".document",
|
@@ -22,17 +23,29 @@ Gem::Specification.new do |s|
|
|
22
23
|
"History.textile",
|
23
24
|
"LICENSE",
|
24
25
|
"README.rdoc",
|
26
|
+
"README.textile",
|
25
27
|
"Rakefile",
|
26
28
|
"VERSION",
|
27
29
|
"container_spec.rb",
|
28
30
|
"lib/om.rb",
|
31
|
+
"lib/om/samples.rb",
|
32
|
+
"lib/om/samples/mods_article.rb",
|
33
|
+
"lib/om/tree_node.rb",
|
29
34
|
"lib/om/xml.rb",
|
30
35
|
"lib/om/xml/accessors.rb",
|
31
36
|
"lib/om/xml/container.rb",
|
37
|
+
"lib/om/xml/document.rb",
|
32
38
|
"lib/om/xml/generator.rb",
|
39
|
+
"lib/om/xml/named_term_proxy.rb",
|
40
|
+
"lib/om/xml/node_generator.rb",
|
33
41
|
"lib/om/xml/properties.rb",
|
34
42
|
"lib/om/xml/property_value_operators.rb",
|
43
|
+
"lib/om/xml/term.rb",
|
44
|
+
"lib/om/xml/term_value_operators.rb",
|
45
|
+
"lib/om/xml/term_xpath_generator.rb",
|
46
|
+
"lib/om/xml/terminology.rb",
|
35
47
|
"lib/om/xml/validation.rb",
|
48
|
+
"lib/om/xml/vocabulary.rb",
|
36
49
|
"om.gemspec",
|
37
50
|
"spec/fixtures/CBF_MODS/ARS0025_016.xml",
|
38
51
|
"spec/fixtures/RUBRIC_mods_article_template.xml",
|
@@ -44,10 +57,19 @@ Gem::Specification.new do |s|
|
|
44
57
|
"spec/spec_helper.rb",
|
45
58
|
"spec/unit/accessors_spec.rb",
|
46
59
|
"spec/unit/container_spec.rb",
|
60
|
+
"spec/unit/document_spec.rb",
|
47
61
|
"spec/unit/generator_spec.rb",
|
62
|
+
"spec/unit/named_term_proxy_spec.rb",
|
63
|
+
"spec/unit/node_generator_spec.rb",
|
48
64
|
"spec/unit/om_spec.rb",
|
49
65
|
"spec/unit/properties_spec.rb",
|
50
66
|
"spec/unit/property_value_operators_spec.rb",
|
67
|
+
"spec/unit/term_builder_spec.rb",
|
68
|
+
"spec/unit/term_spec.rb",
|
69
|
+
"spec/unit/term_value_operators_spec.rb",
|
70
|
+
"spec/unit/term_xpath_generator_spec.rb",
|
71
|
+
"spec/unit/terminology_builder_spec.rb",
|
72
|
+
"spec/unit/terminology_spec.rb",
|
51
73
|
"spec/unit/validation_spec.rb",
|
52
74
|
"spec/unit/xml_spec.rb"
|
53
75
|
]
|
@@ -61,10 +83,19 @@ Gem::Specification.new do |s|
|
|
61
83
|
"spec/spec_helper.rb",
|
62
84
|
"spec/unit/accessors_spec.rb",
|
63
85
|
"spec/unit/container_spec.rb",
|
86
|
+
"spec/unit/document_spec.rb",
|
64
87
|
"spec/unit/generator_spec.rb",
|
88
|
+
"spec/unit/named_term_proxy_spec.rb",
|
89
|
+
"spec/unit/node_generator_spec.rb",
|
65
90
|
"spec/unit/om_spec.rb",
|
66
91
|
"spec/unit/properties_spec.rb",
|
67
92
|
"spec/unit/property_value_operators_spec.rb",
|
93
|
+
"spec/unit/term_builder_spec.rb",
|
94
|
+
"spec/unit/term_spec.rb",
|
95
|
+
"spec/unit/term_value_operators_spec.rb",
|
96
|
+
"spec/unit/term_xpath_generator_spec.rb",
|
97
|
+
"spec/unit/terminology_builder_spec.rb",
|
98
|
+
"spec/unit/terminology_spec.rb",
|
68
99
|
"spec/unit/validation_spec.rb",
|
69
100
|
"spec/unit/xml_spec.rb"
|
70
101
|
]
|
@@ -74,20 +105,20 @@ Gem::Specification.new do |s|
|
|
74
105
|
s.specification_version = 3
|
75
106
|
|
76
107
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
77
|
-
s.add_runtime_dependency(%q<nokogiri>, [">=
|
108
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.2"])
|
78
109
|
s.add_runtime_dependency(%q<facets>, [">= 0"])
|
79
110
|
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
80
111
|
s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
|
81
112
|
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
82
113
|
else
|
83
|
-
s.add_dependency(%q<nokogiri>, [">=
|
114
|
+
s.add_dependency(%q<nokogiri>, [">= 1.4.2"])
|
84
115
|
s.add_dependency(%q<facets>, [">= 0"])
|
85
116
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
86
117
|
s.add_dependency(%q<mocha>, [">= 0.9.8"])
|
87
118
|
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
88
119
|
end
|
89
120
|
else
|
90
|
-
s.add_dependency(%q<nokogiri>, [">=
|
121
|
+
s.add_dependency(%q<nokogiri>, [">= 1.4.2"])
|
91
122
|
s.add_dependency(%q<facets>, [">= 0"])
|
92
123
|
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
93
124
|
s.add_dependency(%q<mocha>, [">= 0.9.8"])
|
@@ -7,22 +7,34 @@ describe "OM::XML::Accessors" do
|
|
7
7
|
before(:all) do
|
8
8
|
class RightsMDTest
|
9
9
|
|
10
|
-
include OM::XML
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
10
|
+
include OM::XML::Document
|
11
|
+
|
12
|
+
terminology = OM::XML::Terminology::Builder.new do |t|
|
13
|
+
t.rightsMetadata(:xmlns=>"http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1", :schema=>"http://github.com/projecthydra/schemas/tree/v1/rightsMetadata.xsd") {
|
14
|
+
t.access {
|
15
|
+
t.human_readable(:path=>"human")
|
16
|
+
t.machine {
|
17
|
+
t.group
|
18
|
+
t.person
|
19
|
+
}
|
20
|
+
}
|
21
|
+
t.edit_access(:variant_of=>:access, :attributes=>{:type=>"personal"})
|
22
|
+
}
|
23
|
+
end
|
24
|
+
# root_property :rightsMetadata, "rightsMetadata", "http://hydra-collab.stanford.edu/schemas/rightsMetadata/v1", :schema=>"http://github.com/projecthydra/schemas/tree/v1/rightsMetadata.xsd"
|
25
|
+
#
|
26
|
+
# property :access, :path=>"access",
|
27
|
+
# :subelements=>[:machine],
|
28
|
+
# :convenience_methods => {
|
29
|
+
# :human_readable => {:path=>"human"}
|
30
|
+
# }
|
31
|
+
#
|
32
|
+
# property :edit_access, :variant_of=>:access, :attributes=>{:type=>"edit"}
|
33
|
+
#
|
34
|
+
# property :machine, :path=>"machine",
|
35
|
+
# :subelements=>["group","person"]
|
24
36
|
|
25
|
-
generate_accessors_from_properties
|
37
|
+
# generate_accessors_from_properties
|
26
38
|
# Generates an empty Mods Article (used when you call ModsArticle.new without passing in existing xml)
|
27
39
|
def self.xml_template
|
28
40
|
builder = Nokogiri::XML::Builder.new do |xml|
|