namely 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +51 -0
  6. data/LICENSE +22 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +125 -0
  9. data/Rakefile +16 -0
  10. data/lib/namely.rb +114 -0
  11. data/lib/namely/authenticator.rb +164 -0
  12. data/lib/namely/country.rb +9 -0
  13. data/lib/namely/currency_type.rb +9 -0
  14. data/lib/namely/event.rb +9 -0
  15. data/lib/namely/exceptions.rb +13 -0
  16. data/lib/namely/field.rb +9 -0
  17. data/lib/namely/job_tier.rb +9 -0
  18. data/lib/namely/profile.rb +13 -0
  19. data/lib/namely/report.rb +9 -0
  20. data/lib/namely/resource_gateway.rb +81 -0
  21. data/lib/namely/restful_model.rb +150 -0
  22. data/lib/namely/version.rb +3 -0
  23. data/namely.gemspec +30 -0
  24. data/spec/fixtures/vcr_cassettes/country_head.yml +51 -0
  25. data/spec/fixtures/vcr_cassettes/country_head_missing.yml +50 -0
  26. data/spec/fixtures/vcr_cassettes/country_index.yml +121 -0
  27. data/spec/fixtures/vcr_cassettes/country_show.yml +68 -0
  28. data/spec/fixtures/vcr_cassettes/country_show_missing.yml +54 -0
  29. data/spec/fixtures/vcr_cassettes/currencytype_index.yml +64 -0
  30. data/spec/fixtures/vcr_cassettes/event_head.yml +51 -0
  31. data/spec/fixtures/vcr_cassettes/event_head_missing.yml +50 -0
  32. data/spec/fixtures/vcr_cassettes/event_index.yml +88 -0
  33. data/spec/fixtures/vcr_cassettes/event_show.yml +62 -0
  34. data/spec/fixtures/vcr_cassettes/event_show_missing.yml +54 -0
  35. data/spec/fixtures/vcr_cassettes/field_index.yml +207 -0
  36. data/spec/fixtures/vcr_cassettes/jobtier_index.yml +103 -0
  37. data/spec/fixtures/vcr_cassettes/profile_create.yml +85 -0
  38. data/spec/fixtures/vcr_cassettes/profile_create_failed.yml +54 -0
  39. data/spec/fixtures/vcr_cassettes/profile_head.yml +51 -0
  40. data/spec/fixtures/vcr_cassettes/profile_head_missing.yml +50 -0
  41. data/spec/fixtures/vcr_cassettes/profile_index.yml +979 -0
  42. data/spec/fixtures/vcr_cassettes/profile_show.yml +91 -0
  43. data/spec/fixtures/vcr_cassettes/profile_show_missing.yml +54 -0
  44. data/spec/fixtures/vcr_cassettes/profile_show_updated.yml +91 -0
  45. data/spec/fixtures/vcr_cassettes/profile_update.yml +95 -0
  46. data/spec/fixtures/vcr_cassettes/profile_update_revert.yml +95 -0
  47. data/spec/fixtures/vcr_cassettes/report_head.yml +51 -0
  48. data/spec/fixtures/vcr_cassettes/report_head_missing.yml +50 -0
  49. data/spec/fixtures/vcr_cassettes/report_show.yml +185 -0
  50. data/spec/fixtures/vcr_cassettes/report_show_missing.yml +54 -0
  51. data/spec/fixtures/vcr_cassettes/token.yml +57 -0
  52. data/spec/fixtures/vcr_cassettes/token_refresh.yml +57 -0
  53. data/spec/namely/authenticator_spec.rb +143 -0
  54. data/spec/namely/configuration_spec.rb +33 -0
  55. data/spec/namely/country_spec.rb +11 -0
  56. data/spec/namely/currency_type_spec.rb +5 -0
  57. data/spec/namely/event_spec.rb +11 -0
  58. data/spec/namely/field_spec.rb +5 -0
  59. data/spec/namely/job_tier_spec.rb +5 -0
  60. data/spec/namely/profile_spec.rb +25 -0
  61. data/spec/namely/report_spec.rb +8 -0
  62. data/spec/namely/resource_gateway_spec.rb +93 -0
  63. data/spec/shared_examples/a_model_with_a_create_action.rb +24 -0
  64. data/spec/shared_examples/a_model_with_a_show_action.rb +38 -0
  65. data/spec/shared_examples/a_model_with_an_index_action.rb +17 -0
  66. data/spec/shared_examples/a_model_with_an_update_action.rb +37 -0
  67. data/spec/spec_helper.rb +49 -0
  68. metadata +280 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c6c9e3f2c619a62f8ecf845c656d50ff12f025d9
4
+ data.tar.gz: e17424ee887917ba69dd1928557bb6cd5c64ab02
5
+ SHA512:
6
+ metadata.gz: 2a9a3dc86ec13b62778feca282add92456013a154dfc8fa5e652a761a9f58350e35ee626184b5bf4aaf60cc47a9d58f56e6aeef156f6204ae16bc58ebdb11a0a
7
+ data.tar.gz: 5a025299aad278901b62a0fc0a24a4977cb4c56aaee28fcbc93f85c65811e70598c400366a487e872f8a78c2d8a19a4f65baecb577e4de15404d7375da07d297
@@ -0,0 +1,3 @@
1
+ .env
2
+ .yardoc
3
+ doc
@@ -0,0 +1,5 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - jruby-19mode
4
+ - 2.0.0
5
+ - 2.1.3
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,51 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ namely (0.0.1)
5
+ backports
6
+ rest_client
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.3.6)
12
+ backports (3.6.3)
13
+ crack (0.4.2)
14
+ safe_yaml (~> 1.0.0)
15
+ diff-lcs (1.2.5)
16
+ dotenv (1.0.2)
17
+ netrc (0.7.9)
18
+ rake (10.3.2)
19
+ rest_client (1.8.1)
20
+ netrc (~> 0.7.7)
21
+ rspec (3.1.0)
22
+ rspec-core (~> 3.1.0)
23
+ rspec-expectations (~> 3.1.0)
24
+ rspec-mocks (~> 3.1.0)
25
+ rspec-core (3.1.7)
26
+ rspec-support (~> 3.1.0)
27
+ rspec-expectations (3.1.2)
28
+ diff-lcs (>= 1.2.0, < 2.0)
29
+ rspec-support (~> 3.1.0)
30
+ rspec-mocks (3.1.3)
31
+ rspec-support (~> 3.1.0)
32
+ rspec-support (3.1.2)
33
+ safe_yaml (1.0.4)
34
+ vcr (2.9.3)
35
+ webmock (1.8.7)
36
+ addressable (>= 2.2.7)
37
+ crack (>= 0.1.7)
38
+ yard (0.8.7.6)
39
+
40
+ PLATFORMS
41
+ ruby
42
+
43
+ DEPENDENCIES
44
+ bundler (~> 1.7)
45
+ dotenv
46
+ namely!
47
+ rake (~> 10.0)
48
+ rspec
49
+ vcr
50
+ webmock
51
+ yard
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Namely
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,125 @@
1
+ # Namely
2
+
3
+ [![Travis](https://travis-ci.org/namely/ruby-client.svg?branch=master)](https://travis-ci.org/namely/ruby-client/builds)
4
+ [![Code Climate](https://codeclimate.com/github/namely/ruby-client/badges/gpa.svg)](https://codeclimate.com/github/namely/ruby-client)
5
+
6
+ TODO: Write a gem description
7
+
8
+ ## Installation
9
+
10
+ Add this line to your application's Gemfile:
11
+
12
+ ```ruby
13
+ gem "namely"
14
+ ```
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install namely
23
+
24
+ ## Configuration
25
+
26
+ You'll need to configure the gem to use your Namely account. Do this
27
+ by setting the `access_token` and `subdomain` variables in a
28
+ configuration block:
29
+
30
+ ```ruby
31
+ Namely.configure do |config|
32
+ config.access_token = "your_access_token"
33
+ config.subdomain = "your-organization"
34
+ end
35
+ ```
36
+
37
+ An access token can be obtained through your organization's Namely
38
+ account.
39
+
40
+ Namely associates a subdomain with your
41
+ organization. organization. For example, if your account is at
42
+ `http://your-organization.namely.com/`, your subdomain would be
43
+ `"your-organization"`.
44
+
45
+ In a Rails application this configuration belongs in
46
+ `config/initializers/namely.rb`.
47
+
48
+ ## Usage Examples
49
+
50
+ ```ruby
51
+ Namely::Country.all.each do |country|
52
+ puts "#{country.id} - #{country.name}"
53
+ end
54
+ # AF - Afghanistan
55
+ # AL - Albania
56
+ # DZ - Algeria
57
+ # AS - American Samoa
58
+ # ...
59
+ ```
60
+
61
+ ```ruby
62
+ if Namely::Country.exists?("BE")
63
+ "Belgium exists!"
64
+ else
65
+ "Hmm."
66
+ end # => "Belgium exists!"
67
+ ```
68
+
69
+ ```ruby
70
+ Namely::Country.find("BE")
71
+ # => <Namely::Country id="BE", name="Belgium", subdivision_type="Province", links={"subdivisions"=>[{"id"=>"BRU", "name"=>"Brussels"}, {"id"=>"VAN", "name"=>"Antwerpen (nl)"}, {"id"=>"VBR", "name"=>"Vlaams Brabant (nl)"}, {"id"=>"VLI", "name"=>"Limburg (nl)"}, {"id"=>"VOV", "name"=>"Oost-Vlaanderen (nl)"}, {"id"=>"VWV", "name"=>"West-Vlaanderen (nl)"}, {"id"=>"WBR", "name"=>"Brabant Wallon (fr)"}, {"id"=>"WHT", "name"=>"Hainaut (fr)"}, {"id"=>"WLG", "name"=>"Liège (fr)"}, {"id"=>"WLX", "name"=>"Luxembourg (fr)"}, {"id"=>"WNA", "name"=>"Namur (fr)"}]}>
72
+ ```
73
+
74
+ ```ruby
75
+ foo_bar = Namely::Profile.create!(
76
+ first_name: "Metasyntactic",
77
+ last_name: "Variable",
78
+ email: "foo_bar@namely.com"
79
+ )
80
+
81
+ foo_bar.id # => "37c919e2-f1c8-4beb-b1d4-a9a36ccc830c"
82
+ ```
83
+
84
+ ## Contributing
85
+
86
+ Wanna help out? Great! Here are a few resources that might help you
87
+ started:
88
+
89
+ * Documentation on [Namely's HTTP API]
90
+ * Namely tries to stick to the [JSON API standard]. If we're seriously
91
+ deviating from it, that may well be a bug.
92
+ * For coding style, we like [thoughtbot's style guide]
93
+
94
+ ### Setting up a development environment
95
+
96
+ The Namely gem uses [dotenv] to manage environment variables. To run
97
+ the tests you'll need to create a `.env` file in the project's root
98
+ directory and assign a few variables in it.
99
+
100
+ Just take this example `.env` file and plug in appropriate values:
101
+
102
+ ```
103
+ TEST_ACCESS_TOKEN=my-sample-access-token
104
+ TEST_SUBDOMAIN=my-sample-subdomain
105
+ ```
106
+
107
+ You'll need admin access to a Namely site to get tokens for these
108
+ variables. You can create application and permanent tokens on the API
109
+ page of the site.
110
+
111
+ ### Submitting your changes
112
+
113
+ 1. [Fork it!]
114
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
115
+ 3. Commit your changes (`git commit -am "Add some feature"`). Be sure
116
+ to include tests!
117
+ 4. Push to the branch (`git push origin my-new-feature`)
118
+ 5. Create a new pull request. We'll review it and leave feedback for
119
+ you ASAP.
120
+
121
+ [Namely's HTTP API]: http://namely.readme.io/v1/docs
122
+ [thoughtbot's style guide]: https://github.com/thoughtbot/guides/tree/master/style
123
+ [JSON API standard]: http://jsonapi.org/
124
+ [dotenv]: https://github.com/bkeepers/dotenv
125
+ [Fork it!]: https://github.com/namely/ruby-client/fork
@@ -0,0 +1,16 @@
1
+ require "rspec/core/rake_task"
2
+ require "bundler/gem_tasks"
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |task|
5
+ task.rspec_opts = ["--color"]
6
+ end
7
+
8
+ task :console do
9
+ exec "irb -r namely -I ./lib"
10
+ end
11
+
12
+ task :documentation do
13
+ exec "yardoc --no-private"
14
+ end
15
+
16
+ task default: :spec
@@ -0,0 +1,114 @@
1
+ require "backports"
2
+ require "json"
3
+ require "ostruct"
4
+ require "rest_client"
5
+
6
+ require "namely/authenticator"
7
+ require "namely/exceptions"
8
+ require "namely/resource_gateway"
9
+ require "namely/restful_model"
10
+
11
+ require "namely/country"
12
+ require "namely/currency_type"
13
+ require "namely/event"
14
+ require "namely/field"
15
+ require "namely/job_tier"
16
+ require "namely/profile"
17
+ require "namely/report"
18
+
19
+ require "namely/version"
20
+
21
+ module Namely
22
+ class << self
23
+ attr_writer :configuration
24
+ end
25
+
26
+ # Return the current configuration.
27
+ #
28
+ # @raise [ImproperlyConfiguredError] if the subdomain or access token
29
+ # haven't been configured.
30
+ #
31
+ # @return [Configuration]
32
+ def self.configuration
33
+ @configuration || raise(
34
+ ImproperlyConfiguredError,
35
+ "Before using the Namely gem, you'll need to configure it with `Namely.configure`."
36
+ )
37
+ end
38
+
39
+ # Set the configuration variables (the subdomain and access token)
40
+ # that allow the Namely gem to access your account.
41
+ #
42
+ # @yieldparam [Configuration] configuration the Configuration
43
+ # object, the attributes of which can be set in the block.
44
+ #
45
+ # @example
46
+ # Namely.configure do |config|
47
+ # config.access_token = "your_access_token"
48
+ # config.subdomain = "your-organization"
49
+ # end
50
+ #
51
+ # @return [void]
52
+ def self.configure
53
+ @configuration ||= Configuration.new
54
+ yield configuration
55
+ end
56
+
57
+ # Return a resource gateway for interfacing with a given resource.
58
+ #
59
+ # @param [String] resource_name
60
+ # @param [String] endpoint
61
+ #
62
+ # @return [ResourceGateway]
63
+ def self.resource_gateway(resource_name, endpoint)
64
+ configuration.resource_gateway(resource_name, endpoint)
65
+ end
66
+
67
+ class Configuration
68
+ attr_writer :access_token, :subdomain
69
+
70
+ # Get the access token.
71
+ #
72
+ # @raise [ImproperlyConfiguredError] if the access token hasn't
73
+ # been configured.
74
+ #
75
+ # @return [String] the access token
76
+ def access_token
77
+ @access_token || raise_missing_variable_error(:access_token)
78
+ end
79
+
80
+ # Get the subdomain.
81
+ #
82
+ # @raise [ImproperlyConfiguredError] if the subdomain hasn't been
83
+ # configured.
84
+ #
85
+ # @return [String] the subdomain
86
+ def subdomain
87
+ @subdomain || raise_missing_variable_error(:subdomain)
88
+ end
89
+
90
+ # Create a resource gateway for interfacing with a given resource.
91
+ #
92
+ # @param [String] resource_name
93
+ # @param [String] endpoint
94
+ #
95
+ # @return [ResourceGateway]
96
+ def resource_gateway(resource_name, endpoint)
97
+ Namely::ResourceGateway.new(
98
+ access_token: access_token,
99
+ endpoint: endpoint,
100
+ resource_name: resource_name,
101
+ subdomain: subdomain
102
+ )
103
+ end
104
+
105
+ private
106
+
107
+ def raise_missing_variable_error(variable)
108
+ raise(
109
+ ImproperlyConfiguredError,
110
+ "The Namely `#{variable}` configuration variable hasn't been set... did you set it when you called `Namely.configure`?"
111
+ )
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,164 @@
1
+ require "cgi"
2
+
3
+ module Namely
4
+ class Authenticator
5
+ # Return a new Authenticator instance.
6
+ #
7
+ # @param [Hash] options
8
+ # @option options [String] client_id
9
+ # @option options [String] client_secret
10
+ #
11
+ # @example
12
+ # authenticator = Authenticator.new(
13
+ # client_id: "my-client-id",
14
+ # client_secret: "my-client-secret"
15
+ # )
16
+ #
17
+ # @return [Authenticator]
18
+ def initialize(options)
19
+ @client_id = options.fetch(:client_id)
20
+ @client_secret = options.fetch(:client_secret)
21
+ end
22
+
23
+ # Returns a URL to begin the authorization code workflow. If you
24
+ # provide a redirect_uri you can receive the server's response.
25
+ #
26
+ # @param [Hash] options
27
+ # @option options [String] host (optional)
28
+ # @option options [String] protocol (optional, defaults to "https")
29
+ # @option options [String] subdomain (required)
30
+ # @option options [String] redirect_uri (optional)
31
+ #
32
+ # @return [String]
33
+ def authorization_code_url(options)
34
+ URL.new(options.merge(
35
+ path: "/api/v1/oauth2/authorize",
36
+ params: {
37
+ response_type: "code",
38
+ approve: "true",
39
+ client_id: client_id,
40
+ },
41
+ )).to_s
42
+ end
43
+
44
+ # Request an access token and refresh token.
45
+ #
46
+ # @param [Hash] options
47
+ # @option options [String] code (required)
48
+ # @option options [String] redirect_uri (required)
49
+ # @option options [String] subdomain (required)
50
+ #
51
+ # @example
52
+ # authenticator = Authenticator.new(
53
+ # client_id: "my-client-id",
54
+ # client_secret: "my-client-secret"
55
+ # )
56
+ #
57
+ # tokens = authenticator.retrieve_tokens(
58
+ # code: "my-code",
59
+ # subdomain: "my-subdomain",
60
+ # redirect_uri: "my-redirect-uri"
61
+ # )
62
+ #
63
+ # tokens["access_token"] # => "my-access-token"
64
+ # tokens["refresh_token"] # => "my-refresh-token"
65
+ # tokens["expires_in"] # => 1234
66
+ # tokens["token_type"] # => "bearer"
67
+ #
68
+ # @return [Hash]
69
+ def retrieve_tokens(options)
70
+ request_tokens(options, "authorization_code", options.fetch(:code))
71
+ end
72
+
73
+ # Get an updated access token using the refresh token.
74
+ #
75
+ # @param [Hash] options
76
+ # @option options [String] redirect_uri (required)
77
+ # @option options [String] refresh_token (required)
78
+ # @option options [String] subdomain (required)
79
+ #
80
+ # @example
81
+ # authenticator = Authenticator.new(
82
+ # client_id: "my-client-id",
83
+ # client_secret: "my-client-secret"
84
+ # )
85
+ #
86
+ # tokens = authenticator.refresh_access_token(
87
+ # redirect_uri: "my-redirect-uri",
88
+ # refresh_token: "my-refresh-token",
89
+ # subdomain: "my-subdomain"
90
+ # )
91
+ #
92
+ # tokens["access_token"] # => "my-access-token"
93
+ # tokens["expires_in"] # => 1234
94
+ # tokens["token_type"] # => "bearer"
95
+ #
96
+ # @return [Hash]
97
+ def refresh_access_token(options)
98
+ request_tokens(options, "refresh_token", options.fetch(:refresh_token))
99
+ end
100
+
101
+ private
102
+
103
+ attr_reader :client_id, :client_secret
104
+
105
+ def request_tokens(options, grant_type, token)
106
+ response = RestClient.post(
107
+ URL.new(options.merge(path: "/api/v1/oauth2/token")).to_s,
108
+ grant_type: grant_type,
109
+ client_id: client_id,
110
+ client_secret: client_secret,
111
+ refresh_token: token,
112
+ )
113
+ JSON.parse(response)
114
+ end
115
+
116
+ class URL
117
+ def initialize(options)
118
+ @options = options
119
+ end
120
+
121
+ def to_s
122
+ "#{protocol}://#{host}#{path}?#{query}"
123
+ end
124
+
125
+ private
126
+
127
+ attr_reader :options
128
+
129
+ def protocol
130
+ options.fetch(:protocol, "https")
131
+ end
132
+
133
+ def host
134
+ if options.has_key?(:subdomain)
135
+ "#{options[:subdomain]}.namely.com"
136
+ else
137
+ options.fetch(:host)
138
+ end
139
+ end
140
+
141
+ def path
142
+ options.fetch(:path)
143
+ end
144
+
145
+ def query
146
+ params.
147
+ map { |key, value| "#{CGI.escape(key.to_s)}=#{CGI.escape(value)}" }.
148
+ join("&")
149
+ end
150
+
151
+ def params
152
+ options.fetch(:params, {}).merge(redirect_uri_param)
153
+ end
154
+
155
+ def redirect_uri_param
156
+ if options.has_key?(:redirect_uri)
157
+ { redirect_uri: options[:redirect_uri] }
158
+ else
159
+ {}
160
+ end
161
+ end
162
+ end
163
+ end
164
+ end