tylerhunt-relax 0.0.5 → 0.1.1

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.
@@ -1,145 +0,0 @@
1
- require 'rubygems'
2
- require 'hpricot'
3
-
4
- module Relax
5
- module Parsers
6
-
7
- ##
8
- # Parses the server's raw response using the Hpricot library.
9
- #
10
- class Hpricot < Base
11
-
12
- FACTORY_NAME = :hpricot
13
-
14
- def initialize(raw, parent)
15
- @xml = ::Hpricot.XML(raw)
16
- super(raw, parent)
17
- end
18
-
19
- def parse!
20
- if parameters
21
- parameters.each do |parameter, options|
22
- begin
23
- element = options[:element] || parameter
24
-
25
- if attribute = options[:attribute] and attribute == true
26
- node = attribute(root, element)
27
- elsif attribute
28
- node = attribute(element(element), attribute)
29
- elsif options[:collection]
30
- node = elements(element)
31
- else
32
- node = element(element)
33
- end
34
-
35
- if options[:collection]
36
- value = node.collect do |element|
37
- options[:collection].new(element)
38
- end
39
- else
40
- case type = options[:type]
41
- when Response
42
- value = type.new(node)
43
-
44
- when :date
45
- value = date_value(node)
46
-
47
- when :time
48
- value = time_value(node)
49
-
50
- when :float
51
- value = float_value(node)
52
-
53
- when :integer
54
- value = integer_value(node)
55
-
56
- when :text
57
- else
58
- value = text_value(node)
59
- end
60
- end
61
-
62
- parent.instance_variable_set("@#{parameter}", value)
63
- rescue ::Hpricot::Error
64
- raise Relax::MissingParameter if options[:required]
65
- end
66
- end
67
- end
68
- end
69
-
70
- # Returns the root of the XML document.
71
- def root
72
- @xml.root
73
- end
74
-
75
- # Checks the name of the root node.
76
- def is?(name)
77
- root.name.gsub(/.*:(.*)/, '\1') == node_name(name)
78
- end
79
-
80
- # Returns a set of elements matching name.
81
- def elements(name)
82
- root.search(root_path(name))
83
- end
84
-
85
- # Returns an element of the specified name.
86
- def element(name)
87
- root.at(root_path(name))
88
- end
89
- alias :has? :element
90
-
91
- # Returns an attribute on an element.
92
- def attribute(element, name)
93
- element[name]
94
- end
95
-
96
- # Gets the value of an element or attribute.
97
- def value(value)
98
- value.is_a?(::Hpricot::Elem) ? value.inner_text : value.to_s
99
- end
100
-
101
- # Gets a text value.
102
- def text_value(value)
103
- value(value)
104
- end
105
-
106
- # Gets an integer value.
107
- def integer_value(value)
108
- value(value).to_i
109
- end
110
-
111
- # Gets a float value.
112
- def float_value(value)
113
- value(value).to_f
114
- end
115
-
116
- # Gets a date value.
117
- def date_value(value)
118
- Date.parse(value(value))
119
- end
120
-
121
- # Gets a time value.
122
- def time_value(value)
123
- Time.parse(value(value))
124
- end
125
-
126
-
127
- private
128
-
129
-
130
- # Converts a name to a node name.
131
- def node_name(name)
132
- name.to_s
133
- end
134
-
135
- # Gets the XPath expression representing the root node.
136
- def root_path(name)
137
- "/#{node_name(name)}"
138
- end
139
-
140
- end
141
-
142
- Factory.register(Hpricot::FACTORY_NAME, Hpricot)
143
-
144
- end
145
- end
@@ -1,158 +0,0 @@
1
- require 'rubygems'
2
- require 'rexml/document'
3
-
4
- module Relax
5
- module Parsers
6
-
7
- ##
8
- # Parsers the server's response using the REXML library.
9
- #
10
- # Benefits:
11
- #
12
- # * XML Namespace support (parameter :foo, :namespace => 'bar')
13
- #
14
- # Drawbacks:
15
- #
16
- # * Case sensitive field names (<Status>..</> != parameter :status)
17
- #
18
- class REXML < Base
19
-
20
- FACTORY_NAME = :rexml
21
-
22
- def initialize(raw, parent)
23
- @xml = ::REXML::Document.new(raw)
24
- super(raw, parent)
25
- end
26
-
27
- def parse!
28
- if parameters
29
- parameters.each do |parameter, options|
30
- begin
31
- element = options[:element] || parameter
32
- namespace = options[:namespace]
33
-
34
- if attribute = options[:attribute] and attribute == true
35
- node = attribute(root, element, namespace)
36
- elsif attribute
37
- node = attribute(element(element), attribute, namespace)
38
- elsif options[:collection]
39
- node = elements(element, namespace)
40
- else
41
- node = element(element, namespace)
42
- end
43
-
44
- if options[:collection]
45
- value = node.collect do |element|
46
- options[:collection].new(element.deep_clone)
47
- end
48
- else
49
- case type = options[:type]
50
- when Response
51
- value = type.new(node)
52
-
53
- when :date
54
- value = date_value(node)
55
-
56
- when :time
57
- value = time_value(node)
58
-
59
- when :float
60
- value = float_value(node)
61
-
62
- when :integer
63
- value = integer_value(node)
64
-
65
- when :text
66
- else
67
- value = text_value(node)
68
- end
69
- end
70
-
71
- parent.instance_variable_set("@#{parameter}", value)
72
- rescue
73
- raise(Relax::MissingParameter) if node.nil? && options[:required]
74
- end
75
- end
76
- end
77
- end
78
-
79
- # Returns the root of the XML document.
80
- def root
81
- @xml.root
82
- end
83
-
84
- # Checks the name of the root node.
85
- def is?(name, namespace = nil)
86
- root.name == node_name(name, nil)
87
- end
88
-
89
- # Returns a set of elements matching name.
90
- def elements(name, namespace = nil)
91
- root.get_elements(node_path(name, namespace))
92
- end
93
-
94
- # Returns an element of the specified name.
95
- def element(name, namespace = nil)
96
- root.elements[node_path(name, namespace)]
97
- end
98
- alias :has? :element
99
-
100
- # Returns an attribute on an element.
101
- def attribute(element, name, namespace = nil)
102
- element.attribute(name)
103
- end
104
-
105
- # Gets the value of an element or attribute.
106
- def value(value)
107
- value.is_a?(::REXML::Element) ? value.text : value.to_s
108
- end
109
-
110
- # Gets a text value.
111
- def text_value(value)
112
- value(value)
113
- end
114
-
115
- # Gets an integer value.
116
- def integer_value(value)
117
- value(value).to_i
118
- end
119
-
120
- # Gets a float value.
121
- def float_value(value)
122
- value(value).to_f
123
- end
124
-
125
- # Gets a date value.
126
- def date_value(value)
127
- Date.parse(value(value))
128
- end
129
-
130
- # Gets a time value.
131
- def time_value(value)
132
- Time.parse(value(value))
133
- end
134
-
135
-
136
- private
137
-
138
-
139
- # Converts a name to a node name.
140
- def node_name(name, namespace = nil)
141
- "#{namespace.to_s + ':' if namespace}#{name}"
142
- end
143
-
144
- # Gets the XPath expression representing the root node.
145
- def root_path(name)
146
- "/#{node_name(name)}"
147
- end
148
-
149
- def node_path(name, namespace = nil)
150
- "#{node_name(name, namespace)}"
151
- end
152
-
153
- end
154
-
155
- Factory.register(REXML::FACTORY_NAME, REXML)
156
-
157
- end
158
- end
data/lib/relax/query.rb DELETED
@@ -1,46 +0,0 @@
1
- require 'cgi'
2
- require 'uri'
3
-
4
- require 'relax/symbolic_hash'
5
-
6
- module Relax
7
- # Query is used to represent the query portion of a URL. It's basically just
8
- # a hash, where each key/value pair is a query parameter.
9
- class Query < SymbolicHash
10
- # Converts the Query to a query string for use in a URL.
11
- def to_s
12
- keys.sort { |a, b| a.to_s <=> b.to_s }.collect do |key|
13
- "#{key.to_s}=#{self.class.escape_value(fetch(key))}"
14
- end.join('&')
15
- end
16
-
17
- class << self
18
- # Parses a URL and returns a Query with its query portion.
19
- def parse(uri)
20
- query = uri.query.split('&').inject({}) do |query, parameter|
21
- key, value = parameter.split('=', 2)
22
- query[unescape_value(key)] = unescape_value(value)
23
- query
24
- end
25
- self.new(query)
26
- end
27
-
28
- # Escapes a query parameter value.
29
- def escape_value(value)
30
- CGI.escape(value.to_s).gsub('%20', '+')
31
- end
32
-
33
- # Unescapes a query parameter value.
34
- def unescape_value(value)
35
- CGI.unescape(value)
36
- end
37
- end
38
-
39
- protected
40
-
41
- # Converts each value of the Query to a string as it's added.
42
- def convert_value(value)
43
- value.to_s
44
- end
45
- end
46
- end
data/lib/relax/request.rb DELETED
@@ -1,95 +0,0 @@
1
- require 'relax/query'
2
-
3
- module Relax
4
- # Request is intended to be a parent class for requests passed to
5
- # Service#call.
6
- class Request
7
- @parameters = {}
8
-
9
- # New takes an optional hash of default parameter values. When passed,
10
- # the values will be set on the request if the key exists as a valid
11
- # parameter name.
12
- def initialize(defaults = {})
13
- # initialize default parameter values
14
- self.class.parameters.each do |parameter, options|
15
- if defaults.has_key?(parameter)
16
- value = defaults[parameter]
17
- elsif options[:value]
18
- value = options[:value]
19
- end
20
-
21
- instance_variable_set("@#{parameter}", value) if value
22
- end
23
- end
24
-
25
- # Converts this request into a Query object.
26
- def to_query
27
- self.class.parameters.keys.inject(Query.new) do |query, key|
28
- value = send(key)
29
- options = self.class.parameters[key]
30
- if value && !options[:type]
31
- query[convert_key(key)] = value if value
32
- elsif options[:type]
33
- options[:type].parameters.each do |parameter, options|
34
- query[convert_complex_key(key, parameter)] = value.send(parameter) if value
35
- end
36
- end
37
- query
38
- end
39
- end
40
-
41
- # Converts this request into a query string for use in a URL.
42
- def to_s
43
- to_query.to_s
44
- end
45
-
46
- # Converts a key when the Request is converted to a query. By default, no
47
- # conversion actually takes place, but this method can be overridden by
48
- # child classes to perform standard manipulations, such as replacing
49
- # underscores.
50
- def convert_key(key)
51
- key
52
- end
53
- protected :convert_key
54
-
55
- # Converts a complex key (i.e. a parameter with a custom type) when the
56
- # Request is converted to a query. By default, this means the key name and
57
- # the parameter name separated by two underscores. This method can be
58
- # overridden by child classes.
59
- def convert_complex_key(key, parameter)
60
- "#{convert_key(key)}.#{convert_key(parameter)}"
61
- end
62
- protected :convert_complex_key
63
-
64
- class << self
65
- # Create the parameters hash for the subclass.
66
- def inherited(subclass) #:nodoc:
67
- subclass.instance_variable_set('@parameters', {})
68
- end
69
-
70
- # Specifies a parameter to create on the request class.
71
- #
72
- # Options:
73
- # - <tt>:type</tt>: An optional custom data type for the parameter.
74
- # This must be a class that is a descendent of Request.
75
- # - <tt>:value</tt>: The default value for this parameter.
76
- def parameter(name, options = {})
77
- attr_accessor name
78
- options = @parameters[name].merge(options) if @parameters.has_key?(name)
79
- @parameters[name] = options
80
- end
81
-
82
- # Adds a template value to a request class. Equivalent to creating a
83
- # parameter with a default value.
84
- def []=(key, value)
85
- parameter(key, {:value => value})
86
- end
87
-
88
- # Returns a hash of all of the parameters for this request, including
89
- # those that are inherited.
90
- def parameters #:nodoc:
91
- (superclass.respond_to?(:parameters) ? superclass.parameters : {}).merge(@parameters)
92
- end
93
- end
94
- end
95
- end
@@ -1,78 +0,0 @@
1
- module Relax
2
- # Response is intended to be a parent class for responses passed to
3
- # Service#call.
4
- #
5
- # A response is in essence an object used to facilitate XML parsing. It
6
- # stores an XML document, and provides access to it through methods like
7
- # #element and #attribute.
8
- class Response
9
- attr_accessor :raw
10
-
11
- # New takes in and parses the raw response.
12
- #
13
- # This will raise a MissingParameter error if a parameterd marked as
14
- # required is not present in the parsed response.
15
- def initialize(xml)
16
- @raw = xml
17
- @parser = Relax::Parsers::Factory.get(parser_name).new(xml.to_s, self)
18
- end
19
-
20
- def parser_name
21
- self.class.instance_variable_get('@parser') || :default
22
- end
23
-
24
- def method_missing(method, *args) #:nodoc:
25
- if @parser.respond_to?(method)
26
- @parser.__send__(method, *args)
27
- else
28
- super
29
- end
30
- end
31
-
32
- class << self
33
- # When a Response is extended, the superclass's parameters are copied
34
- # into the new class. This behavior has the following side-effect: if
35
- # parameters are added to the superclass after it has been extended,
36
- # those new paramters won't be passed on to its children. This shouldn't
37
- # be a problem in most cases.
38
- def inherited(subclass)
39
- @parameters.each do |name, options|
40
- subclass.parameter(name, options)
41
- end if @parameters
42
- subclass.parser(@parser) if @parser
43
- end
44
-
45
- # Specifes a parameter that will be automatically parsed when the
46
- # Response is instantiated.
47
- #
48
- # Options:
49
- # - <tt>:attribute</tt>: An attribute name to use, or <tt>true</tt> to
50
- # use the <tt>:element</tt> value as the attribute name on the root.
51
- # - <tt>:collection</tt>: A class used to instantiate each item when
52
- # selecting a collection of elements.
53
- # - <tt>:element</tt>: The XML element name.
54
- # - <tt>:object</tt>: A class used to instantiate an element.
55
- # - <tt>:type</tt>: The type of the parameter. Should be one of
56
- # <tt>:text</tt>, <tt>:integer</tt>, <tt>:float</tt>, or <tt>:date</tt>.
57
- def parameter(name, options = {})
58
- attr_accessor name
59
- @parameters ||= {}
60
- @parameters[name] = options
61
- end
62
-
63
- # Specifies the parser to use when decoding the server response. If
64
- # no parser is specified for the response, then the default parser will
65
- # be used.
66
- #
67
- # See Relax::Parsers for a list of available parsers.
68
- def parser(name)
69
- @parser ||= name
70
- end
71
-
72
- def ===(response)
73
- response.is_a?(Class) ? response.ancestors.include?(self) : super
74
- end
75
- end
76
-
77
- end
78
- end