relax 0.1.3 → 0.2.0

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.
data/README.rdoc DELETED
@@ -1,194 +0,0 @@
1
- = Relax
2
-
3
- Relax is a library that provides a foundation for writing REST consumer APIs,
4
- including the logic to handle the HTTP requests, build URLs with query
5
- parameters, and parse responses.
6
-
7
-
8
- == Tutorial
9
-
10
- This short tutorial will walk you through the basic steps of creating a simple Flickr API consumer that supports a single call to search for photos by tags.
11
-
12
-
13
- === First Things First
14
-
15
- The first step we'll take is to load the Relax gem.
16
-
17
- require 'rubygems'
18
-
19
- gem 'relax', '~> 0.1.0'
20
- require 'relax'
21
-
22
- Then we'll define our service class.
23
-
24
- class Flickr < Relax::Service
25
- end
26
-
27
-
28
- === Adding an Endpoint
29
-
30
- An endpoint is the base URL for the service we'll be consuming. All of our
31
- actions will be nested inside of an endpoint and build on top of it to
32
- forumlate the final request URL.
33
-
34
- class Flickr < Relax::Service
35
- endpoint 'http://api.flickr.com/services/rest/' do
36
- end
37
- end
38
-
39
-
40
- === Adding Default Parameters
41
-
42
- Since Flickr requires us to always pass an API key parameter let's make that a
43
- required default parameter in our service class.
44
-
45
- class Flickr < Relax::Service
46
- defaults do
47
- parameter :api_key, :required => true
48
- end
49
-
50
- endpoint 'http://api.flickr.com/services/rest/' do
51
- end
52
- end
53
-
54
-
55
- === Adding an Action
56
-
57
- So we have our service now, but we need to define an action before we can
58
- actually fetch any data from it.
59
-
60
- class Flickr < Relax::Service
61
- defaults do
62
- parameter :api_key, :required => true
63
- end
64
-
65
- endpoint 'http://api.flickr.com/services/rest/' do
66
- action :search do
67
- parameter :method, :default => 'flickr.photos.search'
68
- parameter :per_page, :default => 5
69
- parameter :tags
70
- end
71
- end
72
- end
73
-
74
- We're defining an action here called <tt>:search</tt> that will create an
75
- instance method on our service with the same name. There are three parameters,
76
- <tt>:method</tt>, <tt>:per_page</tt>, and <tt>:tags</tt>, with <tt>:method</tt>
77
- and <tt>:per_page</tt> receiving default values.
78
-
79
- There are lots of other parameters for the <tt>flickr.photos.search</tt> method
80
- that we could define, but we'll just stick with these for simplicities sake.
81
-
82
-
83
- === A Small Refactoring
84
-
85
- When adding more methods it will quickly become obvious that we have another
86
- common parameter in <tt>:method</tt>. We can refactor our service class
87
- slightly to make this a default parameter for all of the actions on our
88
- endpoint.
89
-
90
- class Flickr < Relax::Service
91
- defaults do
92
- parameter :api_key, :required => true
93
- end
94
-
95
- endpoint 'http://api.flickr.com/services/rest/' do
96
- defaults do
97
- parameter :method, :required => true
98
- end
99
-
100
- action :search do
101
- set :method, 'flickr.photos.search'
102
- parameter :per_page, :default => 5
103
- parameter :tags
104
- end
105
- end
106
- end
107
-
108
- The <tt>set</tt> method allows us to define a default value for a default
109
- parameter so we don't have to redefine common parameters inside every action.
110
-
111
-
112
- === Defining a Parser
113
-
114
- Before we can actually perform a request we need to let the service know how to
115
- handle the response. This is done by defining a parser.
116
-
117
- class Flickr < Relax::Service
118
- defaults do
119
- parameter :api_key, :required => true
120
- end
121
-
122
- endpoint 'http://api.flickr.com/services/rest/' do
123
- defaults do
124
- parameter :method, :required => true
125
- end
126
-
127
- action :search do
128
- set :method, 'flickr.photos.search'
129
- parameter :per_page, :default => 5
130
- parameter :tags
131
-
132
- parser :rsp do
133
- attribute :stat, :as => :status
134
-
135
- element :photos do
136
- attribute :page
137
- attribute :pages
138
- attribute :perpage, :as => :per_page
139
- attribute :total
140
-
141
- elements :photo do
142
- attribute :id
143
- attribute :owner
144
- attribute :secret
145
- attribute :server
146
- attribute :farm
147
- attribute :title
148
- attribute :ispublic, :as => :is_public
149
- attribute :isfriend, :as => :is_friend
150
- attribute :isfamily, :as => :is_family
151
- end
152
- end
153
- end
154
- end
155
- end
156
- end
157
-
158
- dhe parsing is performed by the Relief gem, so you can find out more about the
159
- syntax in its own documentation.
160
-
161
-
162
- === Making a Call
163
-
164
- Now, we're able to create a new instance of our service with the API key set.
165
-
166
- flickr = Flickr.new(:api_key => FLICKR_API_KEY)
167
-
168
- We can now use this object to search for photos by tag.
169
-
170
- flickr.search(:tags => 'cucumbers,lemons')
171
-
172
- This will return a Ruby response hash.
173
-
174
- {
175
- :status => "ok",
176
- :photos => {
177
- :page => "1",
178
- :pages => "3947",
179
- :per_page => "5",
180
- :total => "19733",
181
- :photo => [
182
- { :is_public => "1", :secret => "3c196485d2", :server => "3182", :is_friend => "0", :farm => "4", :title => "lemons", :is_family => "0", :id => "3509955709", :owner => "37013676@N06" },
183
- { :is_public => "1", :secret => "44f1306a63", :server => "3326", :is_friend => "0", :farm => "4", :title => "Peeto", :is_family => "0", :id => "3509461859", :owner => "13217824@N04" },
184
- { :is_public => "1", :secret => "dce53bce7f", :server => "3364", :is_friend => "0", :farm => "4", :title => "Peeto Above", :is_family => "0", :id => "3509459585", :owner => "13217824@N04" },
185
- { :is_public => "1", :secret => "12f9ba167c", :server => "3632", :is_friend => "0", :farm => "4", :title => "Lemonaid", :is_family => "0", :id => "3509415752", :owner => "35666391@N03" },
186
- { :is_public => "1", :secret => "8caac1ff46", :server => "3320", :is_friend => "0", :farm => "4", :title => "Gardening 365 (Day 8)", :is_family => "0", :id => "3509251322", :owner => "21778017@N06" }
187
- ]
188
- }
189
- }
190
-
191
-
192
- == Copyright
193
-
194
- Copyright (c) 2007-2009 Tyler Hunt. See LICENSE for details.
data/VERSION.yml DELETED
@@ -1,4 +0,0 @@
1
- ---
2
- :major: 0
3
- :minor: 1
4
- :patch: 3
data/lib/relax/action.rb DELETED
@@ -1,49 +0,0 @@
1
- module Relax
2
- class Action
3
- include Contextable
4
-
5
- attr_reader :name
6
-
7
- def initialize(endpoint, name, options, &block)
8
- @endpoint = endpoint
9
- @name = name
10
- @options = options
11
-
12
- extend_context(endpoint)
13
- parse_url_parameters
14
- context.evaluate(&block) if block_given?
15
- end
16
-
17
- def execute(values, options, *args)
18
- args.unshift(values) if values
19
- instance = Instance.new(options, *args)
20
- response = performer(instance, options).perform
21
- context.parse(response)
22
- end
23
-
24
- def method
25
- @options[:method] || :get
26
- end
27
- private :method
28
-
29
- def url
30
- [@endpoint.url, @options[:url]].join
31
- end
32
- private :url
33
-
34
- def performer(instance, options)
35
- values = instance.values(context)
36
- Performer.new(method, url, values, options)
37
- end
38
- private :performer
39
-
40
- def parse_url_parameters
41
- url.scan(/(?:\:)([a-z_]+)/).flatten.each do |name|
42
- defaults do
43
- parameter name.to_sym, :required => true
44
- end
45
- end
46
- end
47
- private :parse_url_parameters
48
- end
49
- end
data/lib/relax/context.rb DELETED
@@ -1,46 +0,0 @@
1
- module Relax
2
- class Context
3
- attr_reader :parameters
4
-
5
- def initialize(parameters=[]) # :nodoc:
6
- @parameters = parameters
7
- end
8
-
9
- def evaluate(&block) # :nodoc:
10
- instance_eval(&block)
11
- end
12
-
13
- def parameter(name, options={})
14
- unless @parameters.find { |parameter| parameter.named?(name) }
15
- @parameters << Parameter.new(name, options)
16
- else
17
- raise ArgumentError.new("Duplicate parameter '#{name}'.")
18
- end
19
- end
20
-
21
- def set(name, value)
22
- if parameter = @parameters.find { |parameter| parameter.named?(name) }
23
- parameter.value = value
24
- end
25
- end
26
-
27
- def parser(root, options={}, &block) # :nodoc:
28
- @parser ||= begin
29
- if root.kind_of?(Class)
30
- root.new(options, &block)
31
- else
32
- Relief::Parser.new(root, options, &block)
33
- end
34
- end
35
- end
36
-
37
- def parse(response) # :nodoc:
38
- @parser.parse(response)
39
- end
40
-
41
- def clone # :nodoc:
42
- cloned_parameters = @parameters.collect { |parameter| parameter.clone }
43
- self.class.new(cloned_parameters)
44
- end
45
- end
46
- end
@@ -1,15 +0,0 @@
1
- module Relax
2
- module Contextable # :nodoc:
3
- def context
4
- @context ||= Context.new
5
- end
6
-
7
- def extend_context(base)
8
- @context = base.context.clone
9
- end
10
-
11
- def defaults(&block)
12
- context.evaluate(&block)
13
- end
14
- end
15
- end
@@ -1,21 +0,0 @@
1
- module Relax
2
- class Endpoint
3
- include Contextable
4
-
5
- attr_reader :url
6
-
7
- def initialize(service, url, options, &block)
8
- @service = service
9
- @url = url
10
- @options = options
11
-
12
- extend_context(service)
13
- instance_eval(&block)
14
- end
15
-
16
- def action(name, options={}, &block)
17
- action = Action.new(self, name, options, &block)
18
- @service.register_action(action)
19
- end
20
- end
21
- end
@@ -1,25 +0,0 @@
1
- module Relax
2
- class Instance # :nodoc:
3
- def initialize(options, *args)
4
- @options = options
5
-
6
- @values = args.inject({}) do |values, arg|
7
- arg.is_a?(Hash) ? values.merge(arg) : values
8
- end
9
- end
10
-
11
- def values(context)
12
- context.parameters.inject({}) do |values, parameter|
13
- name = parameter.options[:as] || parameter.name
14
-
15
- if (value = @values[name] || parameter.value) || @options[:include_blank_values]
16
- values[parameter.name] = value
17
- elsif parameter.required?
18
- raise ArgumentError.new("Missing value for '#{name}'.")
19
- end
20
-
21
- values
22
- end
23
- end
24
- end
25
- end
@@ -1,23 +0,0 @@
1
- module Relax
2
- class Parameter
3
- attr_reader :name, :options
4
- attr_writer :value
5
-
6
- def initialize(name, options={})
7
- @name = name
8
- @options = options
9
- end
10
-
11
- def named?(name)
12
- name == (@options[:as] || @name)
13
- end
14
-
15
- def value
16
- @value || @options[:default]
17
- end
18
-
19
- def required?
20
- @options[:required]
21
- end
22
- end
23
- end
@@ -1,58 +0,0 @@
1
- module Relax
2
- class Performer
3
- def initialize(method, url, values, options={})
4
- @method = method
5
- @url = url
6
- @values = values
7
- @logger = options.delete(:logger)
8
- @credentials = options.delete(:credentials)
9
- @proxy = options.delete(:proxy)
10
- @options = options
11
-
12
- parse_url_tokens
13
- end
14
-
15
- def perform
16
- RestClient.proxy = @proxy if @proxy
17
-
18
- case @method
19
- when :delete, :get, :head
20
- @logger.info "#{@method.to_s.upcase} #{url}" if @logger
21
- RestClient.send(@method, url)
22
- when :post, :put
23
- @logger.info "#{@method.to_s.upcase} #{url}\n#{query}" if @logger
24
- RestClient.send(@method, url, query)
25
- end
26
- end
27
-
28
- def url
29
- url = @url.gsub(/\:[a-z_]+/) do |name|
30
- @url_values[name[1..-1].to_sym]
31
- end
32
-
33
- uri = URI.parse(url)
34
- uri.query = query unless query.nil? || query.empty?
35
- uri.userinfo = @credentials.join(':') if @credentials
36
- uri.to_s
37
- end
38
- private :url
39
-
40
- def query
41
- @values.collect do |name, value|
42
- "#{name}=#{value}" if value || @options[:include_blank_values]
43
- end.compact.join('&')
44
- end
45
- private :query
46
-
47
- def parse_url_tokens
48
- tokens = @url.scan(/(?:\:)([a-z_]+)/).flatten
49
-
50
- @url_values = tokens.inject({}) do |values, name|
51
- name = name.to_sym
52
- values[name] = @values.delete(name) if @values.key?(name)
53
- values
54
- end
55
- end
56
- private :parse_url_tokens
57
- end
58
- end