Class: ActiveDocument::Base

Inherits:
Finder
  • Object
show all
Includes:
ClassLevelInheritableAttributes
Defined in:
lib/ActiveDocument/active_document.rb

Overview

Developers should extend this class to create their own domain classes


= Usage

Dynamic Finders

ActiveDocument::Base provides extensive methods for finding matching documents based on a variety of criteria.

Find By Element

Accessed via find_by_ELEMENT method where Element = the name of your element. Executes a search for all documents with an element ELEMENT that contains the value passed in to the method call. The signature of this dynamic finder is: find_by_ELEMENT(value, root [optional], element_namespace [optional], root_namespace [optional])

Parameters details are as follows: Value: the text to be found within the given element. This is a mandatory parameter Namespace: The namespace in which the element being searched occurs. This is an optional element. If provided, it will be used in the search and will override any default values. If no namespace if provided then the code will attempt to dynamically determine the namespace. First, if the element name is contained in the namespaces hash then that namespace is used. If the element name is not found then the default_namespace is used. If there is no default namespace, then no namespace is used.


== Dynamic Accessors

In addition to the ability to access the underlying XML document (as a Nokogiri XML Document) you have the ability to access the XML as attributes of your domain object via dynamic attribute accessors (eg. domain_object.element_name). Attribute accessors always return instances of ActiveDocument::ActiveDocument::PartialResult. This class works just like a regular ActiveDocument::ActiveDocument::Base object in that you access its members like regular properties.

More complex dynamic accessors are also supported. Instead of just looking for an element anywhere in the document, you can be more specific. For example, domain_object.chapter.paragraph will find all paragraph elements that are children of chapter elements.


Direct Known Subclasses

PartialResult

Defined Under Namespace

Classes: PartialResult

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ClassLevelInheritableAttributes

included

Methods inherited from Finder

co_occurrence, config, execute_attribute_finder, execute_finder, search

Constructor Details

#initialize(xml_string = "", uri = "nil") ⇒ Base

create a new instance with an optional xml string to use for constructing the model



70
71
72
73
74
75
76
77
78
# File 'lib/ActiveDocument/active_document.rb', line 70

def initialize(xml_string = "", uri = "nil")
  @document = Nokogiri::XML(xml_string) do |config|
    config.noblanks
  end
  if !xml_string.empty? then
    @root = @document.root.name
  end
  @uri = uri
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_id, *arguments, &block) ⇒ Object

enables the dynamic property accessors



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/ActiveDocument/active_document.rb', line 116

def method_missing(method_id, * arguments, & block)
  @@log.debug("ActiveDocument::Base at line #{__LINE__}: method called is #{method_id} with arguments #{arguments}")
  method = method_id.to_s
  if method =~ /^(\w*)$/ # methods with no '.' in them and not ending in '='
    if arguments.length > 0
      super
    end
    access_element $1
  elsif method =~ /^(\w*)=$/ && arguments.length == 1 # methods with no '.' in them and ending in '='
    set_element($1, arguments)
  else
    super
  end
end

Class Attribute Details

.default_namespace(namespace) ⇒ Object (readonly)

Returns the value of attribute default_namespace.



133
134
135
# File 'lib/ActiveDocument/active_document.rb', line 133

def default_namespace
  @default_namespace
end

.namespaces(namespace_hash) ⇒ Object (readonly)

Returns the value of attribute namespaces.



133
134
135
# File 'lib/ActiveDocument/active_document.rb', line 133

def namespaces
  @namespaces
end

.root(root) ⇒ Object (readonly)

Returns the value of attribute root.



133
134
135
# File 'lib/ActiveDocument/active_document.rb', line 133

def root
  @root
end

Instance Attribute Details

#documentObject (readonly)

Returns the value of attribute document.



66
67
68
# File 'lib/ActiveDocument/active_document.rb', line 66

def document
  @document
end

#my_attribute_namespacesObject (readonly)

Returns the value of attribute my_attribute_namespaces.



66
67
68
# File 'lib/ActiveDocument/active_document.rb', line 66

def my_attribute_namespaces
  @my_attribute_namespaces
end

#my_default_attribute_namespacesObject (readonly)

Returns the value of attribute my_default_attribute_namespaces.



66
67
68
# File 'lib/ActiveDocument/active_document.rb', line 66

def my_default_attribute_namespaces
  @my_default_attribute_namespaces
end

#my_default_namespaceObject (readonly)

Returns the value of attribute my_default_namespace.



66
67
68
# File 'lib/ActiveDocument/active_document.rb', line 66

def my_default_namespace
  @my_default_namespace
end

#my_namespacesObject (readonly)

Returns the value of attribute my_namespaces.



66
67
68
# File 'lib/ActiveDocument/active_document.rb', line 66

def my_namespaces
  @my_namespaces
end

#rootObject (readonly)

Returns the root element for this object



98
99
100
# File 'lib/ActiveDocument/active_document.rb', line 98

def root
  @root
end

#uriObject (readonly)

Returns the value of attribute uri.



66
67
68
# File 'lib/ActiveDocument/active_document.rb', line 66

def uri
  @uri
end

Class Method Details

.add_attribute_namespace(attribute, uri) ⇒ Object



167
168
169
# File 'lib/ActiveDocument/active_document.rb', line 167

def add_attribute_namespace(attribute, uri)
  @my_attribute_namespaces[attribute.to_s] == uri
end

.add_namespace(element, uri) ⇒ Object



163
164
165
# File 'lib/ActiveDocument/active_document.rb', line 163

def add_namespace(element, uri)
  @my_namespaces[element.to_s] == uri
end

.attribute_namespaces(namespace_hash) ⇒ Object



159
160
161
# File 'lib/ActiveDocument/active_document.rb', line 159

def attribute_namespaces(namespace_hash)
  @my_attribute_namespaces = namespace_hash
end

.default_attribute_namespace(namespace) ⇒ Object



187
188
189
# File 'lib/ActiveDocument/active_document.rb', line 187

def default_attribute_namespace(namespace)
  @my_default_attribute_namespace = namespace # todo should this just be an entry in namespaces?
end

.delete(uri) ⇒ Object



191
192
193
# File 'lib/ActiveDocument/active_document.rb', line 191

def delete(uri)
  @@ml_http.send_xquery(@@xquery_builder.delete(uri))
end

.find_by_word(word, root = @root, namespace = @my_default_namespace) ⇒ Object

Finds all documents of this type that contain the word anywhere in their structure



271
272
273
274
275
# File 'lib/ActiveDocument/active_document.rb', line 271

def find_by_word(word, root=@root, namespace=@my_default_namespace)
  xquery = @@xquery_builder.find_by_word(word, root, namespace)
  @@log.info("ActiveDocument.execute_find_by_word at line #{__LINE__}: #{xquery}")
  SearchResults.new(@@ml_http.send_xquery(xquery))
end

.load(uri) ⇒ Object

Returns an ActiveXML object representing the requested information. If no document exists at that uri then a LoadException is thrown



262
263
264
265
266
267
268
# File 'lib/ActiveDocument/active_document.rb', line 262

def load(uri)
  document = @@ml_http.send_xquery(@@xquery_builder.load(uri))
  if document.empty?
    raise LoadException, "File #{uri} not found", caller
  end
  self.new(document, uri)
end

.method_missing(method_id, *arguments, &block) ⇒ Object

enables the dynamic finders



196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
# File 'lib/ActiveDocument/active_document.rb', line 196

def method_missing(method_id, * arguments, & block)
  @@log.debug("ActiveDocument::Base at line #{__LINE__}: method called is #{method_id} with arguments #{arguments}")
  method = method_id.to_s
  # identify attribute search methods
  if method =~ /find_by_attribute_(.*)$/ and arguments.length >= 2
    attribute = $1.to_sym
    element = arguments[0]
    value = arguments[1]
    if arguments[2]
      root = arguments[2]
    else
      root = @root || self.class.name
    end
    if arguments[3]
      element_namespace = arguments[3]
    else
      element_namespace = namespace_for_element(element)
    end
    if arguments[4]
      attribute_namespace = arguments[4]
    else
      attribute_namespace = namespace_for_attribute(attribute)
    end
    if arguments[5]
      root_namespace = arguments[5]
    else
      root_namespace = namespace_for_element(root)
    end
    if arguments[6]
      options = arguments[6]
    else
      options = nil
    end
    execute_attribute_finder(element, attribute, value, root, element_namespace, attribute_namespace, root_namespace, options)
  elsif method =~ /find_by_(.*)$/ and arguments.length > 0 # identify element search methods
    value = arguments[0]
    element = $1.to_sym
    if arguments[1]
      root = arguments[1]
    else
      root = @root
    end
    if arguments[2]
      element_namespace = arguments[2]
    else
      element_namespace = namespace_for_element(element)
    end
    if arguments[3]
      root_namespace = arguments[3]
    else
      root_namespace = namespace_for_element(root)
    end
    if arguments[4]
      options = arguments[4]
    else
      options = nil
    end
    execute_finder(element, value, root, element_namespace, root_namespace, options)
  else
    super
  end

end

.namespace_for_attribute(attribute) ⇒ Object



145
146
147
148
149
150
151
152
153
# File 'lib/ActiveDocument/active_document.rb', line 145

def namespace_for_attribute(attribute)
  namespace = nil
  if !@my_attribute_namespaces.nil? && @my_attribute_namespaces[attribute]
    namespace = @my_attribute_namespaces[attribute]
  else
    namespace = @my_default_attribute_namespace unless @my_default_attribute_namespace.nil?
  end
  namespace
end

.namespace_for_element(element) ⇒ Object



135
136
137
138
139
140
141
142
143
# File 'lib/ActiveDocument/active_document.rb', line 135

def namespace_for_element(element)
  namespace = nil
  if !@my_namespaces.nil? && @my_namespaces[element]
    namespace = @my_namespaces[element]
  else
    namespace = @my_default_namespace unless @my_default_namespace.nil?
  end
  namespace
end

.remove_attribute_namespace(attribute) ⇒ Object



175
176
177
# File 'lib/ActiveDocument/active_document.rb', line 175

def remove_attribute_namespace(attribute)
  @my_attribute_namespaces.delete attribute
end

.remove_namespace(element) ⇒ Object



171
172
173
# File 'lib/ActiveDocument/active_document.rb', line 171

def remove_namespace(element)
  @my_namespaces.delete element
end

Instance Method Details

#[](key) ⇒ Object



102
103
104
105
106
107
108
109
# File 'lib/ActiveDocument/active_document.rb', line 102

def [](key)
  namespace = namespace_for_element(key)
  if namespace.nil? || namespace.empty?
    @document.root.xpath("@#{key}").to_s
  else
    @document.root.xpath("@ns:#{key}", {'ns' => namespace}).to_s
  end
end

#[]=(key, value) ⇒ Object



111
112
113
# File 'lib/ActiveDocument/active_document.rb', line 111

def []=(key, value)
  set_attribute(key, value)
end

#save(uri = nil) ⇒ Object

saves this document to the repository. If uri is provided then that will be the value used for the uri. If no uri was passed in then the existing value or the uri is used, unless uri is nil in which case an exception will be thrown



87
88
89
90
91
92
93
94
95
# File 'lib/ActiveDocument/active_document.rb', line 87

def save(uri = nil)
  doc_uri = (uri || @uri)
  if doc_uri then
    @@ml_http.send_xquery(@@xquery_builder.save(self, doc_uri))
  else
    raise ArgumentError, "uri must not be nil", caller
  end

end

#to_sObject



80
81
82
# File 'lib/ActiveDocument/active_document.rb', line 80

def to_s
  @document.to_xml(:save_with => Nokogiri::XML::Node::SaveOptions::NO_DECLARATION)
end