tylerhunt-relax 0.0.5 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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