om 3.1.0 → 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/{COMMON_OM_PATTERNS.textile → COMMON_OM_PATTERNS.md} +136 -126
  3. data/CONTRIBUTING.md +2 -2
  4. data/GETTING_FANCY.md +153 -0
  5. data/GETTING_STARTED.md +329 -0
  6. data/Gemfile +1 -1
  7. data/History.md +164 -0
  8. data/LICENSE +15 -20
  9. data/QUERYING_DOCUMENTS.md +162 -0
  10. data/README.md +2 -2
  11. data/UPDATING_DOCUMENTS.md +6 -0
  12. data/gemfiles/gemfile.rails3 +1 -1
  13. data/gemfiles/gemfile.rails4 +1 -1
  14. data/lib/om/version.rb +1 -1
  15. data/lib/om/xml/dynamic_node.rb +42 -51
  16. data/lib/tasks/om.rake +1 -1
  17. data/om.gemspec +1 -2
  18. data/spec/integration/differentiated_elements_spec.rb +2 -2
  19. data/spec/integration/element_value_spec.rb +13 -13
  20. data/spec/integration/proxies_and_ref_spec.rb +10 -10
  21. data/spec/integration/querying_documents_spec.rb +20 -27
  22. data/spec/integration/rights_metadata_integration_example_spec.rb +4 -4
  23. data/spec/integration/selective_querying_spec.rb +1 -1
  24. data/spec/integration/serialization_spec.rb +15 -15
  25. data/spec/integration/set_reentrant_terminology_spec.rb +6 -6
  26. data/spec/integration/subclass_terminology_spec.rb +8 -8
  27. data/spec/integration/xpathy_stuff_spec.rb +10 -10
  28. data/spec/unit/container_spec.rb +27 -27
  29. data/spec/unit/document_spec.rb +24 -24
  30. data/spec/unit/dynamic_node_spec.rb +60 -49
  31. data/spec/unit/named_term_proxy_spec.rb +12 -7
  32. data/spec/unit/node_generator_spec.rb +4 -4
  33. data/spec/unit/nokogiri_sanity_spec.rb +17 -18
  34. data/spec/unit/om_spec.rb +2 -2
  35. data/spec/unit/template_registry_spec.rb +51 -51
  36. data/spec/unit/term_builder_spec.rb +45 -44
  37. data/spec/unit/term_spec.rb +55 -55
  38. data/spec/unit/term_value_operators_spec.rb +205 -205
  39. data/spec/unit/term_xpath_generator_spec.rb +33 -36
  40. data/spec/unit/terminology_builder_spec.rb +50 -47
  41. data/spec/unit/terminology_spec.rb +92 -92
  42. data/spec/unit/validation_spec.rb +12 -12
  43. data/spec/unit/xml_serialization_spec.rb +20 -20
  44. data/spec/unit/xml_spec.rb +3 -3
  45. data/spec/unit/xml_terminology_based_solrizer_spec.rb +18 -18
  46. metadata +11 -38
  47. data/GETTING_FANCY.textile +0 -145
  48. data/GETTING_STARTED.textile +0 -254
  49. data/History.textile +0 -186
  50. data/QUERYING_DOCUMENTS.textile +0 -139
  51. data/UPDATING_DOCUMENTS.textile +0 -3
@@ -0,0 +1,329 @@
1
+ # OM (Opinionated Metadata) - Getting Started
2
+
3
+ OM allows you to define a “terminology” to ease translation between XML
4
+ and ruby objects - you can query the xml for Nodes *or* node values
5
+ without ever writing a line of XPath.
6
+
7
+ OM “terms” are ruby symbols you define (in the terminology) that map
8
+ specific XML content into ruby object attributes.
9
+
10
+ The API documentation at [http://rdoc.info/github/projecthydra/om]
11
+ provides additional, more targeted information. We will provide links to
12
+ the API as appropriate.
13
+
14
+ ## What you will learn from this document
15
+
16
+ 1. Install OM and run it in IRB
17
+ 2. Build an OM Terminology
18
+ 3. Use OM XML Document class
19
+ 4. Create XML from the OM XML Document
20
+ 5. Load existing XML into an OM XML Document
21
+ 6. Query OM XML Document to get term values
22
+ 7. Access the Terminology of an OM XML Document
23
+ 8. Retrieve XPath from the terminology
24
+
25
+ ## Install OM
26
+
27
+ To get started, you will create a new folder, set up a Gemfile to
28
+ install OM, and then run bundler.
29
+
30
+ ```bash
31
+ mkdir omtest
32
+ cd omtest
33
+ ```
34
+
35
+ Using whichever editor you prefer, create a file (in omtest directory)
36
+ called Gemfile with the following contents:
37
+
38
+ ```ruby
39
+ source 'https://rubygems.org'
40
+ gem 'om'
41
+ ```
42
+
43
+ Now run bundler to install the gem: (you will need the bundler Gem)
44
+
45
+ bundle install
46
+
47
+ You should now be set to use irb to run the following example.
48
+
49
+ ## Build a simple OM terminology (in irb)
50
+
51
+ To experiment with abbreviated terminology examples, irb is your friend.
52
+ If you are working on a persistent terminology and have to experiment to
53
+ make sure you declare your terminology correctly, we recommend writing
54
+ test code (e.g. with rspec). You can see examples of this
55
+ [here](https://github.com/projecthydra/hydra-tutorial-application/blob/master/spec/models/journal_article_mods_datastream_spec.rb)
56
+
57
+ ```irb
58
+ irb
59
+ require "rubygems"
60
+ => true
61
+ require "om"
62
+ => true
63
+ ```
64
+
65
+ Create a simple (simplish?) Terminology Builder
66
+ ([OM::XML::Terminology::Builder](OM/XML/Terminology/Builder.html))
67
+ based on a couple of elements from the MODS schema.
68
+
69
+ ```ruby
70
+ terminology_builder = OM::XML::Terminology::Builder.new do |t|
71
+ t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
72
+ # This is a mods:name. The underscore is purely to avoid namespace conflicts.
73
+ t.name_ {
74
+ t.namePart
75
+ t.role(:ref=>[:role])
76
+ t.family_name(:path=>"namePart", :attributes=>{:type=>"family"})
77
+ t.given_name(:path=>"namePart", :attributes=>{:type=>"given"}, :label=>"first name")
78
+ t.terms_of_address(:path=>"namePart", :attributes=>{:type=>"termsOfAddress"})
79
+ }
80
+
81
+ # Re-use the structure of a :name Term with a different @type attribute
82
+ t.person(:ref=>:name, :attributes=>{:type=>"personal"})
83
+ t.organization(:ref=>:name, :attributes=>{:type=>"corporate"})
84
+
85
+ # This is a mods:role, which is used within mods:namePart elements
86
+ t.role {
87
+ t.text(:path=>"roleTerm",:attributes=>{:type=>"text"})
88
+ t.code(:path=>"roleTerm",:attributes=>{:type=>"code"})
89
+ }
90
+ end
91
+ ```
92
+
93
+ Now tell the Terminology Builder to build your
94
+ [OM::XML::Terminology](OM/XML/Terminology.html):
95
+
96
+ terminology = terminology_builder.build
97
+
98
+ ## OM Documents
99
+
100
+ Generally you will use an [OM::XML::Document](OM/XML/Document.html) to
101
+ work with your xml. Here’s how to define a Document class that uses the
102
+ same Terminology as above.
103
+
104
+ In a separate window (so you can keep irb running), create the file
105
+ `my_mods_document.rb` in the omtest directory, with this content:
106
+
107
+ ```ruby
108
+ class MyModsDocument < ActiveFedora::NokogiriDatastream
109
+ include OM::XML::Document
110
+
111
+ set_terminology do |t|
112
+ t.root(:path=>"mods", :xmlns=>"http://www.loc.gov/mods/v3", :schema=>"http://www.loc.gov/standards/mods/v3/mods-3-2.xsd")
113
+ # This is a mods:name. The underscore is purely to avoid namespace conflicts.
114
+ t.name_ {
115
+ t.namePart
116
+ t.role(:ref=>[:role])
117
+ t.family_name(:path=>"namePart", :attributes=>{:type=>"family"})
118
+ t.given_name(:path=>"namePart", :attributes=>{:type=>"given"}, :label=>"first name")
119
+ t.terms_of_address(:path=>"namePart", :attributes=>{:type=>"termsOfAddress"})
120
+ }
121
+ t.person(:ref=>:name, :attributes=>{:type=>"personal"})
122
+ t.organization(:ref=>:name, :attributes=>{:type=>"corporate"})
123
+
124
+ # This is a mods:role, which is used within mods:namePart elements
125
+ t.role {
126
+ t.text(:path=>"roleTerm",:attributes=>{:type=>"text"})
127
+ t.code(:path=>"roleTerm",:attributes=>{:type=>"code"})
128
+ }
129
+ end
130
+
131
+ # Generates an empty Mods Article (used when you call ModsArticle.new without passing in existing xml)
132
+ # (overrides default behavior of creating a plain xml document)
133
+ def self.xml_template
134
+ # use Nokogiri to build the XML
135
+ builder = Nokogiri::XML::Builder.new do |xml|
136
+ xml.mods(:version=>"3.3", "xmlns:xlink"=>"http://www.w3.org/1999/xlink",
137
+ "xmlns:xsi"=>"http://www.w3.org/2001/XMLSchema-instance",
138
+ "xmlns"=>"http://www.loc.gov/mods/v3",
139
+ "xsi:schemaLocation"=>"http://www.loc.gov/mods/v3 http://www.loc.gov/standards/mods/v3/mods-3-3.xsd") {
140
+ xml.titleInfo(:lang=>"") {
141
+ xml.title
142
+ }
143
+ xml.name(:type=>"personal") {
144
+ xml.namePart(:type=>"given")
145
+ xml.namePart(:type=>"family")
146
+ xml.affiliation
147
+ xml.computing_id
148
+ xml.description
149
+ xml.role {
150
+ xml.roleTerm("Author", :authority=>"marcrelator", :type=>"text")
151
+ }
152
+ }
153
+ }
154
+ end
155
+ # return a Nokogiri::XML::Document, not an OM::XML::Document
156
+ return builder.doc
157
+ end
158
+ end
159
+ ```
160
+
161
+ (Note that we are now also using the ActiveFedora gem.)
162
+
163
+ [OM::XML::Document](OM/XML/Document.html) provides the `set_terminology`
164
+ method to handle the details of creating a TerminologyBuilder and
165
+ building the terminology for you. This allows you to focus on defining
166
+ the structures of the Terminology itself.
167
+
168
+ ### Creating XML Documents from Scratch using OM
169
+
170
+ By default, new OM Document instances will create an empty xml document,
171
+ but if you override `self.xml_template` to return a different object
172
+ (e.g.
173
+ [Nokogiri::XML::Document](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html)),
174
+ that will be created instead.
175
+
176
+ In the example above, we have overridden `xml_template` to build an
177
+ empty, relatively simple MODS document as a
178
+ [Nokogiri::XML::Document](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html).
179
+ We use
180
+ [Nokogiri::XML::Builder](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Builder.html)
181
+ and call its .doc method at the end of xml\_template in order to return
182
+ the
183
+ [Nokogiri::XML::Document](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html)
184
+ object. Instead of using
185
+ [Nokogiri::XML::Builder](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Builder.html),
186
+ you could put your template into an actual xml file and have
187
+ xml\_template use
188
+ [Nokogiri::XML::Document.parse](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html#M000225)
189
+ to load it. That’s up to you. Create the documents however you want, just return a
190
+ [Nokogiri::XML::Document](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html).
191
+
192
+ To use
193
+ [Nokogiri::XML::Builder](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Builder.html)
194
+
195
+ ```
196
+ require "my_mods_document"
197
+ newdoc = MyModsDocument.new
198
+ newdoc.to_xml
199
+ => NoMethodError: undefined method `to_xml' for nil:NilClass
200
+ ```
201
+
202
+ ### Loading an existing XML document with OM
203
+
204
+ To load existing XML into your OM Document, use
205
+ [#from_xml](OM/XML/Container/ClassMethods.html#from_xml-instance_method")
206
+
207
+ For an example, download
208
+ [hydrangea_article1.xml](https://github.com/projecthydra/om/blob/master/spec/fixtures/mods_articles/hydrangea_article1.xml)
209
+ into your working directory (omtest), then run this in irb:
210
+
211
+ ```ruby
212
+ sample_xml = File.new("hydrangea_article1.xml")
213
+ doc = MyModsDocument.from_xml(sample_xml)
214
+ ```
215
+
216
+ Take a look at the document object’s xml that you’ve just populated. We
217
+ will use this document for the next few examples.
218
+
219
+ ```ruby
220
+ doc.to_xml
221
+ ```
222
+
223
+ ### Querying OM Documents
224
+
225
+ Using the Terminology associated with your Document, you can query the
226
+ xml for nodes *or* node values without ever writing a line of XPath.
227
+
228
+ You can use OM::XML::Document.find\_by\_terms to retrieve xml *nodes*
229
+ from the datastream. It returns Nokogiri::XML::Node objects:
230
+
231
+ ```ruby
232
+ doc.find_by_terms(:person)
233
+ doc.find_by_terms(:person).length
234
+ doc.find_by_terms(:person).each {|n| puts n.to_xml}
235
+ ```
236
+
237
+ You might prefer to use nodes as a way of getting multiple values
238
+ pertaining to a node, rather than doing more expensive lookups for each
239
+ desired value.
240
+
241
+ If you want to get directly to the *values* within those nodes, use
242
+ `OM::XML::Document.term_values`:
243
+
244
+ ```ruby
245
+ doc.term_values(:person, :given_name)
246
+ doc.term_values(:person, :family_name)
247
+ ```
248
+
249
+ If the xpath points to XML nodes that contain other nodes, the response
250
+ to `term_values` will contain `Nokogiri::XML::Node` objects instead of text
251
+ values:
252
+
253
+ ```ruby
254
+ doc.term_values(:name)
255
+ ```
256
+
257
+ For more examples of Querying OM Documents, see [Querying
258
+ Documents](https://github.com/projecthydra/om/blob/master/QUERYING_DOCUMENTS.md)
259
+
260
+ ### Updating, Inserting & Deleting Elements (TermValueOperators)
261
+
262
+ For more examples of Updating OM Documents, see [Updating
263
+ Documents](https://github.com/projecthydra/om/blob/master/UPDATING_DOCUMENTS.md)
264
+
265
+ ### Validating Documents
266
+
267
+ If you have an XML schema defined in your Terminology’s root Term, you
268
+ can validate any xml document by calling `.validate` on any instance of
269
+ your Document classes.
270
+
271
+ ```ruby
272
+ doc.validate
273
+ ```
274
+
275
+ **Note:** this method *requires an internet connection*, as it will
276
+ download the XML schema from the URL you have specified in the
277
+ Terminology’s root term.
278
+
279
+ ### Directly accessing the [Nokogiri::XML::Document](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html) and the [OM::XML::Terminology](https://github.com/projecthydra/om/blob/master/lib/om/xml/terminology.rb)
280
+
281
+ [OM::XML::Document](https://github.com/projecthydra/om/blob/master/lib/om/xml/document.rb)
282
+ is implemented as a container for a
283
+ [Nokogiri::XML::Document](http://nokogiri.rubyforge.org/nokogiri/Nokogiri/XML/Document.html).
284
+ It uses the associated OM Terminology to provide a bunch of convenience
285
+ methods that wrap calls to Nokogiri. If you ever need to operate
286
+ directly on the Nokogiri Document, simply call ng\_xml and do what you
287
+ need to do. OM will not get in your way.
288
+
289
+ ```ruby
290
+ ng_document = doc.ng_xml
291
+ ```
292
+
293
+ If you need to look at the Terminology associated with your Document,
294
+ call
295
+ [#terminology](OM/XML/Document/ClassMethods.html#terminology-instance_method)
296
+ on the Document’s *class*.
297
+
298
+ ```ruby
299
+ MyModsDocument.terminology
300
+ doc.class.terminology
301
+ ```
302
+
303
+ ### Using a Terminology to generate XPath Queries based on Term Pointers
304
+
305
+ Because the Terminology is essentially a mapping from XPath queries to
306
+ ruby object attributes, in most cases you won’t need to know the actual
307
+ XPath queries. Nevertheless, when you *do* want to know the Xpath
308
+ (e.g. for ensuring your terminology is correct) for a term, the
309
+ Terminology can generate xpath queries based on the structures you’ve
310
+ defined ([OM::XML::TermXPathGenerator](OM/XML/TermXpathGenerator.html)).
311
+
312
+ Here are the xpaths for `:name` and two variants of `:name` that were
313
+ created using the `:ref` argument in the Terminology Builder:
314
+
315
+ ```irb
316
+ terminology.xpath_for(:name)
317
+ => "//oxns:name"
318
+ terminology.xpath_for(:person)
319
+ => "//oxns:name[@type=\"personal\"]"
320
+ terminology.xpath_for(:organization)
321
+ => "//oxns:name[@type=\"corporate\"]"
322
+ ```
323
+
324
+ ### Solrizing Documents
325
+
326
+ The solrizer gem provides support for indexing XML documents into Solr
327
+ based on OM Terminologies. That process is documented in the [solrizer
328
+ documentation](http://rdoc.info/github/projecthydra/solrizer).
329
+
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
@@ -0,0 +1,164 @@
1
+ - 2014-09-11: Use HTTPS URLs for RubyGems [Michael Slone]
2
+
3
+ ### 3.1.0 (17 Jul 2014)
4
+ - 2014-07-17: Bump solrizer version to \~\> 3.3 [Justin Coyne]
5
+ - 2014-07-17: Use the system libxml2 on travis [Justin Coyne]
6
+ - 2014-07-17: Remove dependency on mediashelf-loggable [Justin Coyne]
7
+ - 2014-06-13: Setting values on a proxy term should build the parent terms if they don’t exist [Justin Coyne]
8
+ - 2014-06-05: Handle invalid time for Rails 3 [Justin Coyne]
9
+ - 2014-06-02: Updating solrizer, correcting rspec deprecations [Adam Wead]
10
+
11
+ ### 3.0.1 (25 Jun 2013)
12
+ - Fix bug where values that were the same as the existing values were removed from the update list
13
+
14
+ ### 3.0.0 (20 Jun 2013)
15
+ - Return an array instead of a hash Term\#update\_values
16
+ - When passing an array to Term\#update\_values, it will overwrite all of the existing values of that term.
17
+ - OM::XML::Document\#find\_by\_terms\_and\_value should match strings with text() = xpath query, rather than contains().
18
+
19
+ ### 2.2.1 (20 Jun 2013)
20
+ - Revert deprecation of passing Hash values
21
+
22
+ ### 2.2.0 (20 June 2013)
23
+ - Deprecate passing Hash values into DynamicNode\#val= or
24
+ - Document\#update\_attributes. This behavior will be removed in 3.0.0
25
+ - Rails 4 support
26
+ - Pass nil in order to remove a node (instead of blank string)
27
+
28
+ ### 2.1.2 (3 May 2013)
29
+ - Fix missing comma after exception
30
+
31
+ ### 2.1.1 (2 May 2013)
32
+ - bump solrizer to 3.1.0
33
+
34
+ ### 2.1.0 (29 April 2013)
35
+ - support for element names with periods in them
36
+ - support for ‘type: :time’
37
+
38
+ ### 2.0.0
39
+ - Support new solr schema
40
+
41
+ ### 1.8.0
42
+ - Removed unused mods\_article\_terminology.xml
43
+ - Replacing :data\_type with :type; deprecating :data\_type
44
+ - Making test related to HYDRA-647 pending
45
+ - Adding .type method for ruby 1.8.7 compatibility
46
+ - XML serialization should use the data\_type node name and not type
47
+ - Update homepage in gemspec
48
+ - Remove .rvmrc
49
+ - Remove debugger from gemfile
50
+
51
+ ### 1.7.0
52
+ - Add casting to dates and integers when you specify the :type attribute on a terminology node
53
+
54
+ ### 1.6.1
55
+ - Integration spec to illustrate selective querying.
56
+ - Add \#use\_terminology and \#extend\_terminology methods to extend existing OM terminologies
57
+
58
+ ### 1.6.0
59
+ - Delegate all methods on the dynamic node to the found values
60
+ - Allow arrays to be set on dynamic nodes
61
+
62
+ ### 1.5.3
63
+ - HYDRA-657 OM Terms that share a name with methods on Nokogiri Builders
64
+ have incorrect builder templates
65
+ - HYDRA-674 XML Builder templates incorrect for :none attributes
66
+
67
+ ### 1.5.2
68
+ - HYDRA-742 Can’t modify frozen string (parameters in rails 3.2, when using ruby 1.9.3)
69
+
70
+ ### 1.5.1
71
+ - HYDRA-737 OM tests fail under ree 1.8.7-2011.12 (Fix also applies to ruby 1.8.7-p357)
72
+
73
+ ### 1.5.0
74
+ - HYDRA-358 Added support for namespaceless terminologies
75
+
76
+ ### 1.4.4
77
+ - HYDRA-415 [https://jira.duraspace.org/browse/HYDRA-415] Fixed insert of attribute nodes
78
+ - update to rspec2
79
+ - compatibility fixes for ruby 1.9
80
+ - RedCloth updated to 4.2.9
81
+ - Replace local ‘delimited_list’ logic with `Array#join`
82
+
83
+ ### 1.4.3
84
+ - HYDRA-681 https://jira.duraspace.org/browse/HYDRA-681 Om was calling
85
+ `.dirty` when updating nodes, it should only do that when it’s operating on a `Nokogiri:Datastream`
86
+ - HYDRA-682 https://jira.duraspace.org/browse/HYDRA-682 Om first level terms support update
87
+
88
+ ### 1.4.2
89
+ - [HYDRA-667](https://jira.duraspace.org/browse/HYDRA-667) Fixed bug where
90
+ updating nodes wasn’t marking the document as dirty
91
+
92
+ ### 1.4.0
93
+ - Added dynamic node access DSL. Added a warning when calling an index on a proxy term.
94
+
95
+ ### 1.3.0
96
+ - Document automatically includes Validation module, meaning that you can
97
+ now call .validate on any document
98
+
99
+ ### 1.2.4
100
+ - TerminologyBuilder.root now passes on its options to the root term builder that it creates.
101
+
102
+ ### 1.2.3
103
+ - NamedTermProxies can now point to terms at the root of a Terminology
104
+
105
+ ### 1.2.0
106
+ - Added OM::XML::TemplateRegistry for built-in templating and creation of new XML nodes
107
+
108
+ ### 1.1.1
109
+ - [HYDRA-395](https://jira.duraspace.org/browse/HYDRA-395): Fixed bug that
110
+ prevented you from appending term values with apostrophes in them
111
+
112
+ ### 1.1.0
113
+ - HYDRA-371: Provide a way to specify a term that points to nodes where an attribute is not set
114
+
115
+ Add support for this syntax in Terminologies, where an attribute value
116
+ can be :none. When an attribute’s value is set to :none, a not()
117
+ predicate is used in the resulting xpath
118
+
119
+ ```ruby
120
+ t.computing\_id(:path=\>“namePart”, :attributes=\>{:type=\>:none})
121
+ ```
122
+
123
+ will result in an xpath that looks like:
124
+
125
+ ```
126
+ //namePart[not(@type)]
127
+ namePart[not(@type)]
128
+ ```
129
+
130
+ ### 1.0.1
131
+ - HYDRA-329: Allow for NamedTermProxies at root of Terminology
132
+
133
+ ### 1.0.0
134
+ **Stable release**
135
+
136
+ ### 0.1.10
137
+ - Improving generation of constrained xpath queries
138
+
139
+ ### 0.1.9
140
+ - Improving support for deeply nested nodes (still needs work though)
141
+
142
+ ### 0.1.5
143
+ - root\_property now inserts an entry into the properties hash
144
+ - added `.generate` method for building new instances of declared properties
145
+ - refinements to accessor\_xpath
146
+
147
+ ### 0.1.4
148
+ - made attribute\_xpath idempotent
149
+
150
+ ### 0.1.3
151
+ - added accessor\_generic\_name and accessor\_hierarchical\_name methods
152
+
153
+ ### 0.1.2
154
+ - changed syntax for looking up accessors with (optional) index values
155
+ — no using [{:person=\>1}, :first\_name] instead of [:person, 1, :first\_name]
156
+
157
+ ### 0.1.1
158
+ - RENAMED to om (formerly opinionated-xml)
159
+ - broke up functionality into Modules
160
+ - added `OM::XML::Accessor` functionality
161
+
162
+ ### 0.1
163
+ - Note: OX v.1 Does not handle treating attribute values as the changing “value” of a node
164
+