axel 0.0.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.
Files changed (128) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +21 -0
  3. data/.octopolo.yml +2 -0
  4. data/.rspec +2 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/.travis.yml +23 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +271 -0
  11. data/Rakefile +13 -0
  12. data/app/models/axel/api_proxy.rb +86 -0
  13. data/app/models/axel/associations/base.rb +64 -0
  14. data/app/models/axel/associations/belongs_to.rb +43 -0
  15. data/app/models/axel/associations/has_many.rb +29 -0
  16. data/app/models/axel/associations/has_one.rb +30 -0
  17. data/app/models/axel/payload.rb +4 -0
  18. data/app/models/axel/payload/base.rb +107 -0
  19. data/app/models/axel/payload/errors.rb +62 -0
  20. data/app/models/axel/payload/metadata.rb +57 -0
  21. data/app/models/axel/querier.rb +166 -0
  22. data/app/models/axel/router.rb +119 -0
  23. data/app/models/axel/service_resource.rb +4 -0
  24. data/app/models/axel/service_resource/associations.rb +80 -0
  25. data/app/models/axel/service_resource/attributes.rb +23 -0
  26. data/app/models/axel/service_resource/automatic_resource.rb +23 -0
  27. data/app/models/axel/service_resource/base.rb +47 -0
  28. data/app/models/axel/service_resource/builder.rb +40 -0
  29. data/app/models/axel/service_resource/inspects.rb +17 -0
  30. data/app/models/axel/service_resource/payload_parser.rb +46 -0
  31. data/app/models/axel/service_resource/queries.rb +25 -0
  32. data/app/models/axel/service_resource/requesters.rb +49 -0
  33. data/app/models/axel/service_resource/routes.rb +19 -0
  34. data/app/models/axel/service_resource/typhoid_extensions.rb +134 -0
  35. data/app/views/axel/base/empty.json.erb +0 -0
  36. data/app/views/axel/base/empty.xml.builder +0 -0
  37. data/app/views/layouts/axel.json.jbuilder +7 -0
  38. data/app/views/layouts/axel.xml.builder +12 -0
  39. data/axel.gemspec +42 -0
  40. data/lib/axel.rb +56 -0
  41. data/lib/axel/application_extensions.rb +13 -0
  42. data/lib/axel/application_helper.rb +27 -0
  43. data/lib/axel/base_controller.rb +6 -0
  44. data/lib/axel/cascadable_attribute.rb +33 -0
  45. data/lib/axel/configurations/resource.rb +29 -0
  46. data/lib/axel/configurations/service.rb +28 -0
  47. data/lib/axel/configurator.rb +54 -0
  48. data/lib/axel/configurators/services.rb +29 -0
  49. data/lib/axel/controller_base.rb +27 -0
  50. data/lib/axel/controller_helpers.rb +209 -0
  51. data/lib/axel/controller_parameters.rb +32 -0
  52. data/lib/axel/engine.rb +14 -0
  53. data/lib/axel/inspector.rb +91 -0
  54. data/lib/axel/payload/remote_error.rb +14 -0
  55. data/lib/axel/request_options.rb +26 -0
  56. data/lib/axel/uri.rb +47 -0
  57. data/lib/axel/version.rb +3 -0
  58. data/lib/generators/axel/install_generator.rb +16 -0
  59. data/lib/generators/templates/README.md +22 -0
  60. data/lib/generators/templates/axel.rb +81 -0
  61. data/script/rails +5 -0
  62. data/spec/controllers/pages_controller_spec.rb +217 -0
  63. data/spec/dummy/README.rdoc +261 -0
  64. data/spec/dummy/Rakefile +7 -0
  65. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  66. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  67. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  68. data/spec/dummy/app/controllers/pages_controller.rb +6 -0
  69. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  70. data/spec/dummy/app/mailers/.gitkeep +0 -0
  71. data/spec/dummy/app/models/.gitkeep +0 -0
  72. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  73. data/spec/dummy/config.ru +4 -0
  74. data/spec/dummy/config/application.rb +62 -0
  75. data/spec/dummy/config/boot.rb +10 -0
  76. data/spec/dummy/config/database.yml +25 -0
  77. data/spec/dummy/config/environment.rb +5 -0
  78. data/spec/dummy/config/environments/development.rb +37 -0
  79. data/spec/dummy/config/environments/production.rb +67 -0
  80. data/spec/dummy/config/environments/test.rb +37 -0
  81. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  82. data/spec/dummy/config/initializers/inflections.rb +15 -0
  83. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  84. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  85. data/spec/dummy/config/initializers/session_store.rb +8 -0
  86. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  87. data/spec/dummy/config/locales/en.yml +5 -0
  88. data/spec/dummy/config/routes.rb +3 -0
  89. data/spec/dummy/db/development.sqlite3 +0 -0
  90. data/spec/dummy/db/test.sqlite3 +0 -0
  91. data/spec/dummy/lib/assets/.gitkeep +0 -0
  92. data/spec/dummy/log/.gitignore +1 -0
  93. data/spec/dummy/log/.gitkeep +0 -0
  94. data/spec/dummy/public/404.html +26 -0
  95. data/spec/dummy/public/422.html +26 -0
  96. data/spec/dummy/public/500.html +25 -0
  97. data/spec/dummy/public/favicon.ico +0 -0
  98. data/spec/dummy/script/rails +6 -0
  99. data/spec/envelope_integration_check.rb +96 -0
  100. data/spec/helpers/axel/application_helper_spec.rb +31 -0
  101. data/spec/lib/axel/associations/base_spec.rb +28 -0
  102. data/spec/lib/axel/associations/belongs_to_spec.rb +62 -0
  103. data/spec/lib/axel/associations/has_many_spec.rb +23 -0
  104. data/spec/lib/axel/associations/has_one_spec.rb +23 -0
  105. data/spec/lib/axel/configurations/resource_spec.rb +15 -0
  106. data/spec/lib/axel/configurations/service_spec.rb +31 -0
  107. data/spec/lib/axel/configurator_spec.rb +26 -0
  108. data/spec/lib/axel/configurators/services_spec.rb +37 -0
  109. data/spec/lib/axel/controller_base_spec.rb +16 -0
  110. data/spec/lib/axel/controller_parameters_spec.rb +31 -0
  111. data/spec/lib/axel/inspector_spec.rb +45 -0
  112. data/spec/lib/axel/request_options_spec.rb +50 -0
  113. data/spec/lib/axel/uri_spec.rb +42 -0
  114. data/spec/lib/axel_spec.rb +64 -0
  115. data/spec/models/axel/api_proxy_spec.rb +66 -0
  116. data/spec/models/axel/payload/errors_spec.rb +165 -0
  117. data/spec/models/axel/payload/metadata_spec.rb +141 -0
  118. data/spec/models/axel/querier_spec.rb +158 -0
  119. data/spec/models/axel/router_spec.rb +115 -0
  120. data/spec/models/axel/service_resource/base_spec.rb +244 -0
  121. data/spec/models/axel/service_resource/builder_spec.rb +64 -0
  122. data/spec/models/axel/service_resource/payload_parser_spec.rb +60 -0
  123. data/spec/spec_helper.rb +39 -0
  124. data/spec/support/address.rb +5 -0
  125. data/spec/support/persona.rb +15 -0
  126. data/spec/support/user.rb +6 -0
  127. data/spec/views/axel/base/empty_spec.rb +34 -0
  128. metadata +508 -0
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZjgxOWQxNTg1OTVmYjU3OWZhMWFhZGUxMjczNDY0M2Q0Y2NlNDJkOQ==
5
+ data.tar.gz: !binary |-
6
+ MTE2MjQ1ZDUwNDc4MTQyZTBmY2EwYzU0NjdmN2VhOWM5ZWY4MjZiMA==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ Nzc5ODRlOWZhZjU2M2ExNTYyZmM5YTdjMWUwMmIwYWE3M2IwNjY0MmIyNmIw
10
+ NGVmZDRiMWRkMWRmZmFlOGM4ZTE5MmUzYjNkMjdkZDUxMzNlMmQ4Yjk3NjQ1
11
+ YjQ1ZGQzODczYWJiNTExMTdhYTkyZDBkNWY4ODgwNjU0YWZiM2U=
12
+ data.tar.gz: !binary |-
13
+ ZWZlYWVhM2VjZGNjMjBlNGY3ODM1ZTczNTVjZWE5ZWRiZTY4OGYwYmRhN2Yx
14
+ MWUwN2JjM2UxZTk2MGU4MjQ5ODUwMTExOWMwY2NjNGJjNGMwNzgzNTA5MzI4
15
+ ZjE5MWI2NDdmMGMzNjYyM2NmODZkNGRmMmRlMWI2YWY0ZmFjMGY=
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
17
+ .idea
18
+
19
+ cache
20
+
21
+ Gemfile.lock
@@ -0,0 +1,2 @@
1
+ deploy_branch: master
2
+ github_repo: sportngin/axel
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
@@ -0,0 +1 @@
1
+ axel
@@ -0,0 +1 @@
1
+ 1.9.3
@@ -0,0 +1,23 @@
1
+ sudo: false
2
+ branches:
3
+ only:
4
+ - master
5
+
6
+ notifications:
7
+ slack: sportngin:Yr24DXJUvIOegSPwKMG099D1
8
+
9
+ after_script:
10
+ - uptime && vmstat -S M
11
+
12
+ language: ruby
13
+ rvm:
14
+ - 1.9.3
15
+ - 2.0.0
16
+ - 2.1.0
17
+ - 2.2
18
+
19
+ cache: bundler
20
+
21
+ script:
22
+ - bundle exec rake spec
23
+
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in axel.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Sport Ngin
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,271 @@
1
+ # Axel
2
+ [![Build Status](https://magnum.travis-ci.com/sportngin/axel.svg?token=JKgYC4kfXqjpwsFoBpzq)](https://magnum.travis-ci.com/sportngin/axel)
3
+
4
+ The building blocks for building a Sport Ngin Back-end API service:
5
+
6
+ * add some error helpers (error object)
7
+ * standardized XML/JSON envelope (metadata/error/result objects)
8
+ * adding `suppress_response_codes` to params will force a 200 and will only show errors
9
+ in the error object of the response body
10
+ * standard controller responders to ensure JSON is always prefered, XML is acceptable, and
11
+ the response always has a correct body that handles all errors
12
+
13
+ ## Installation
14
+
15
+ Add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ source 'https://D9W5miiTyaf8EzrkWdTy@gem.fury.io/me/' # BELOW THE `source rubygems`
19
+ gem 'axel'
20
+ ```
21
+
22
+ Then execute:
23
+
24
+ ```bash
25
+ $ bundle
26
+ ```
27
+
28
+ In your `app/controllers/application_controller.rb` (or wherever your base class is that will
29
+ use these helpers) change to:
30
+
31
+ ```ruby
32
+ class ApplicationController < ActionController::Base
33
+ include Axel::ControllerHelpers
34
+ end
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### Controller Specific Helpers
40
+
41
+ #### Errors
42
+
43
+ Errors object is available (as `errors`) from any controller:
44
+
45
+ ```ruby
46
+ errors.header_status # suppress_response_codes param will set to 200 by default
47
+ errors << "Error message!" # add error messages
48
+ errors.display # { status: errors.status_code, messages: errors.messages }
49
+ errors.display? # Display errors? (was there an error added or status changed?)
50
+ errors.messages
51
+ errors.messages = []
52
+ errors.status = :not_found
53
+ errors.status_code # => 404
54
+ errors.status = 403
55
+ errors.status_code # => 403
56
+ errors.new_error(status, *m) # set status, add an error or list of errors (not in an array object)
57
+
58
+ # Can also set on the fly:
59
+ rescue_error status: :not_found, message: "Error!"
60
+ rescue_error status: :unproccessable_entity, messages: ["Error!", "Error2!"]
61
+ ```
62
+
63
+ #### Metadata
64
+
65
+ Metadata object that will be placed on every outgoing response body. You can add to the object like
66
+ so:
67
+
68
+ ```ruby
69
+ metadata[:current_user] = current_user
70
+
71
+ # the body will then set this on the outgoing body:
72
+ # => { "metadata": { "current_user": "..." }, "result": "...", "...": "..." }
73
+ ```
74
+
75
+ #### Responders
76
+ At the top of each controller (for APIs) should be:
77
+
78
+ ```ruby
79
+ respond_to_json_xml
80
+ ```
81
+
82
+ This defines `respond_to :json, :xml`.
83
+
84
+ making these responders good to use for defaults:
85
+
86
+ ```ruby
87
+ respond_with_action :show # Good for the end of a create to show the created object
88
+ render_action :show
89
+ respond_to_empty # Render empty `result`, fill in `metadata`, `error` if necessary
90
+ render_empty
91
+ ```
92
+
93
+ #### Resource finder
94
+
95
+ `find_resource` will automatically find a resource:
96
+
97
+ ```ruby
98
+ class PostsController < ApplicationController
99
+ before_filter :find_resource
100
+ def show
101
+ respond_with
102
+ end
103
+ end
104
+
105
+ curl http://localhost:3000/posts/1 # finds Post 1 and renders
106
+ curl http://localhost:3000/posts/1
107
+ # => {"metadata":{},"error":{"status":404,"messages":["Record not found"]},"result":null}
108
+
109
+ # can also customize the find_resource with `finder` and `value`
110
+ # were `finder` is column and `value` is the value of the column
111
+ ```
112
+
113
+ #### Param helpers
114
+
115
+ ```ruby
116
+ query_params # Only params on the query string
117
+ post_params # POST params
118
+ object_params # Either params under the object name (ie. {"user":".."} or all POST params
119
+ object_name # singularized controller name for finding object_params
120
+ ```
121
+
122
+ #### General workflow helpers
123
+
124
+ Helpers:
125
+
126
+ ```ruby
127
+ force_ssl! # raises Errors::ForceSSL
128
+ drop_meta! # we don't want the requester to get data like current_user, etc.
129
+ drop_meta? # Did we call `drop_meta!`?
130
+ format # The format passed from the request OR JSON
131
+ render_nil_format # This is for rendering nils in json or XML (XML is blank, JSON is "null")
132
+ safe_json_load # If you've already manually rendered some to json this helper safely loads it to a hash for re-JSONing
133
+ ```
134
+
135
+ Errors are rescued to make for easier API workflow and responding:
136
+
137
+ ```ruby
138
+ Axel::Errors::ForceSSL # Drop meta
139
+ # Status: Forbidden
140
+ # Message: SSL is required
141
+
142
+ ActiveRecord::RecordNotFound # Status: 404
143
+ # Message: Record not found
144
+
145
+ Axel::Errors::NotAuthorized # Status: 401
146
+ # Message: User not authorized
147
+
148
+ ActiveModel::MassAssignmentSecurity::Error # Status: 422
149
+ # Message: Unacceptable parameter being used
150
+ ```
151
+
152
+ ### Interservice Helpers
153
+
154
+ #### Some setup examples
155
+
156
+ ```ruby
157
+ Axel.config do |config|
158
+ config.add_resource :user_service,
159
+ :group,
160
+ service: { url: "https://user-service.your-platform.com" }
161
+
162
+ # Custom Path (otherwise defaults to plural of the resource_name (:user => "/users"))
163
+ # config.add_resource :user_service,
164
+ # :user,
165
+ # service: { url: "https://user-service.your-platform.com" },
166
+ # attributes: [:user_name, :first_name],
167
+ # path: "owner"
168
+ end
169
+
170
+ class Group < Axel::ServiceResource::Base
171
+ # Let's say your class doesn't match the configured resource, you can:
172
+ resource_name :group
173
+
174
+ # Setup fields (gets accessors, all available in #attributes)
175
+ field :name
176
+ field :owner_id
177
+ field :owner_type
178
+ field :uri
179
+
180
+ route "/groups/mine", :mine
181
+ route "/user/:user_id/groups", :by_user_id
182
+
183
+ # Attached to every Group request, you can define instance defaults as well
184
+ def self.default_request_options
185
+ { headers: { "Accepts" => "stuff!", Authorization: "Bearer #{some_access_token}" } }
186
+ end
187
+ end
188
+
189
+ group = Group.new name: "test", owner_id: 1, owner_type: "Organization", uri: "blargh"
190
+ group.save
191
+
192
+ my_groups = Group.mine
193
+ user_groups = Group.by_user_id(1)
194
+ user_groups = Group.by_user_id(user_id: 1)
195
+
196
+ a_group = Group.find(1)
197
+ ```
198
+
199
+ #### Related data!
200
+
201
+ ```ruby
202
+ class User < Axel::ServiceResource::Base
203
+ has_many :personas
204
+ has_one :email_address, class: Email, included: true
205
+ end
206
+
207
+ class Email < Axel::ServiceResource::Base
208
+ belongs_to :user, find_nested: true
209
+ end
210
+
211
+ class Persona < Axel::ServiceResource::Base
212
+ belongs_to :user
213
+ end
214
+
215
+ u = User.find(1)
216
+ u.personas # => API call to /users/1/personas puts data in an array of Persona objects
217
+ u.email_address # => Uses `email_address` in the User data to put into Email objects
218
+ Persona.find(1).user # => API call to /users/#{persona.user_id} fills User object
219
+ Email.find(1).user # => API call to /personas/1/user fills User Object
220
+ ```
221
+
222
+ #### Some Chainable Query methods
223
+ ```ruby
224
+ Group.where(name: "test")
225
+ # => https://user-service.your-platform.com/groups?name=test
226
+
227
+ Group.all params: { name: "test" }, body: jsonified_stuffs, headers: {}, method: :post
228
+
229
+ Group.uri("https://user-service.dev/groups").where(name: "Jon").all(headers: {})
230
+ # => http://user-service.dev/groups?name=Jon
231
+
232
+ Group.uri("https://user-service.dev").at_path("/other_groups_path").where name: "test"
233
+ # => http://user-service.dev/other_groups_path?name=test
234
+
235
+ Group.where(name: "Jon").all(headers: {}).none
236
+ # => [] # Will always be empty array
237
+
238
+ Group.none.where(name: "Jon")
239
+ # => [] # can chain
240
+
241
+ Group.without_default_path.at_path("groupies")
242
+ # => https://user-service.your-platform.com/groupies
243
+
244
+ # Enumerable works!
245
+ Groups.where(name: "test").each { |g| puts e.attributes.inspect }
246
+ groups = Groups.where(name: "test").to_a
247
+
248
+ # drop cached JSON, then you can requery
249
+ groups.reload.where(owner_id: 1)
250
+ ```
251
+
252
+ #### More General Usage
253
+ ``` ruby
254
+ new_user.metadata # => { .. } # Metadata section of JSON output
255
+ new_user.metadata[:current_user] # => { "id"=>1, "user_name"=>"admin", "first_name"=>"Happy", "last_name"=>"Gilmore", "uri"=>"http://user-service.dev/users/1"}
256
+ new_user.errors.status_code # => 200
257
+ new_user.errors.messages # => []
258
+ new_user.result # => { ... } # Main envelope JSON body
259
+ ```
260
+ For more info on what the requester is and can do check out
261
+ [Axel::ServiceResource::Base][srb]
262
+
263
+ ## Contributing
264
+
265
+ 1. Fork it
266
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
267
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
268
+ 4. Push to the branch (`git push origin my-new-feature`)
269
+ 5. Create new Pull Request
270
+
271
+ [srb]: http://github.com/sportngin/axel/tree/master/app/models/axel/service_resource/base.rb
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env rake
2
+ require "rspec/core/rake_task"
3
+ require "bundler/gem_tasks"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+
7
+ namespace :spec do
8
+ RSpec::Core::RakeTask.new(:docs) do |t|
9
+ t.rspec_opts = ["--format doc"]
10
+ end
11
+ end
12
+
13
+ task :default => :spec
@@ -0,0 +1,86 @@
1
+ module Axel
2
+ class ApiProxy < ServiceResource::Base
3
+ attr_reader :endpoint
4
+ attr_reader :services
5
+ attr_reader :request_options
6
+
7
+ def self.cache_file
8
+ cache_dir.join("api_registry_cache.json")
9
+ end
10
+
11
+ def self.cache_dir
12
+ Rails.root.join("cache")
13
+ end
14
+
15
+ def self.build(_, response)
16
+ if response.success?
17
+ MultiJson.load(response.body)
18
+ else
19
+ {}
20
+ end
21
+ rescue MultiJson::DecodeError
22
+ {}
23
+ end
24
+
25
+ def initialize(endpoint, request_options = {})
26
+ @endpoint = endpoint
27
+ @request_options = {}
28
+ end
29
+
30
+ def register!
31
+ resource_settings.each do |resource_setting|
32
+ Axel.config do |config|
33
+ config.add_resource extract_service_name(resource_setting["service"]),
34
+ extract_resource_name(resource_setting["path"]),
35
+ service: { url: resource_setting["service"] }
36
+ end
37
+ end
38
+ end
39
+
40
+ def make_cache
41
+ Dir.exists?(self.class.cache_dir) ? true : Dir.mkdir(self.class.cache_dir)
42
+ end
43
+ private :make_cache
44
+
45
+ def write_cache(to_cache)
46
+ make_cache
47
+ File.open(self.class.cache_file, 'w') { |file| file.write to_cache.to_json }
48
+ to_cache
49
+ end
50
+ private :write_cache
51
+
52
+ def open_json(string_data)
53
+ begin
54
+ MultiJson.load string_data
55
+ rescue MultiJson::DecodeError
56
+ []
57
+ end
58
+ end
59
+ private :open_json
60
+
61
+ def read_cache
62
+ File.exists?(self.class.cache_file) ? open_json(File.open(self.class.cache_file).read) : []
63
+ end
64
+ private :read_cache
65
+
66
+ def resource_settings
67
+ fresh = self.class.request(endpoint, "/registry.json", request_options)
68
+ if fresh.has_key? "routes"
69
+ write_cache fresh["routes"]
70
+ else
71
+ read_cache
72
+ end
73
+ end
74
+ private :resource_settings
75
+
76
+ def extract_service_name(service_url)
77
+ service_url.gsub(/http[s]*\:\/\//,"").gsub(/\..*$/, "").underscore
78
+ end
79
+ private :extract_service_name
80
+
81
+ def extract_resource_name(resource_path)
82
+ resource_path.gsub(/^\//, "")
83
+ end
84
+ private :extract_resource_name
85
+ end
86
+ end