From 81c148de7908a7244f5645f8e3bd75ca272f3d04 Mon Sep 17 00:00:00 2001 From: Derek Lindahl Date: Thu, 26 Mar 2015 19:01:25 -0700 Subject: [PATCH] Code formatting changes (guided by Rubocop) --- .editorconfig | 2 +- .gitignore | 2 +- .irbrc | 2 +- .rubocop.yml | 45 ++++++++++++ Appraisals | 2 +- LICENSE | 2 +- README.md | 30 ++++---- Rakefile | 2 +- lib/frenetic.rb | 23 ++++--- lib/frenetic/briefly_memoizable.rb | 16 +++-- .../concerns/collection_rest_methods.rb | 9 ++- lib/frenetic/concerns/hal_linked.rb | 21 +++--- lib/frenetic/concerns/member_rest_methods.rb | 17 ++--- lib/frenetic/concerns/structured.rb | 4 +- lib/frenetic/connection.rb | 43 +++++++----- lib/frenetic/errors.rb | 69 ++++++++++++++++++- lib/frenetic/hypermedia_link.rb | 45 +++++------- lib/frenetic/hypermedia_link_set.rb | 25 +++---- lib/frenetic/middleware/hal_json.rb | 7 +- lib/frenetic/resource.rb | 52 ++++++++------ lib/frenetic/resource_collection.rb | 6 +- lib/frenetic/resource_mockery.rb | 10 +-- lib/frenetic/version.rb | 2 +- spec/briefly_memoizable_spec.rb | 2 +- spec/concerns/hal_linked_spec.rb | 10 +-- spec/concerns/member_rest_methods_spec.rb | 2 +- spec/concerns/structured_spec.rb | 11 +-- spec/connection_spec.rb | 2 +- spec/fixtures/test_api_requests.rb | 60 ++++++++-------- spec/frenetic_spec.rb | 6 +- spec/hypermedia_link_set_spec.rb | 6 +- spec/hypermedia_link_spec.rb | 2 +- spec/middleware/hal_json_spec.rb | 6 +- spec/resource_collection_spec.rb | 7 +- spec/resource_mockery_spec.rb | 6 +- spec/resource_spec.rb | 12 ++-- spec/spec_helper.rb | 2 +- spec/support/rspec.rb | 2 +- spec/support/timecop.rb | 2 +- spec/support/webmock.rb | 2 +- 40 files changed, 348 insertions(+), 228 deletions(-) create mode 100644 .rubocop.yml diff --git a/.editorconfig b/.editorconfig index 8e73f2e..d1e55ef 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,4 @@ indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true -insert_final_newline = true \ No newline at end of file +insert_final_newline = true diff --git a/.gitignore b/.gitignore index 68ae0ce..70f1406 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,4 @@ spec/reports test/tmp test/version_tmp tmp -vendor \ No newline at end of file +vendor diff --git a/.irbrc b/.irbrc index 33f4aa2..9fbab72 100644 --- a/.irbrc +++ b/.irbrc @@ -1,3 +1,3 @@ require 'bundler' Bundler.require -require 'awesome_print' \ No newline at end of file +require 'awesome_print' diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..66644c5 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,45 @@ +AllCops: + Exclude: + - '*.gemspec' + +Metrics/ClassLength: + Max: 120 + +Metrics/LineLength: + Max: 100 + +Metrics/MethodLength: + Max: 15 + +Style/AccessModifierIndentation: + Enabled: false + +Style/ClassVars: + Enabled: false + +Style/ConstantName: + Enabled: false + +Style/Documentation: + Enabled: false + +Style/NegatedIf: + Enabled: false + +Style/RaiseArgs: + Enabled: false + +Style/SpaceAfterColon: + Enabled: false + +Style/SpaceBeforeBlockBraces: + Enabled: false + +Style/SpaceInsideBlockBraces: + Enabled: false + +Style/SpaceInsideParens: + Enabled: false + +Style/TrivialAccessors: + Enabled: false diff --git a/Appraisals b/Appraisals index f50db59..9f52b8a 100644 --- a/Appraisals +++ b/Appraisals @@ -6,4 +6,4 @@ end appraise 'faraday-09' do gem 'faraday', '~> 0.9.0' gem 'faraday_middleware', '~> 0.9.0' -end \ No newline at end of file +end diff --git a/LICENSE b/LICENSE index 5fb4920..b1546af 100644 --- a/LICENSE +++ b/LICENSE @@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index ab29998..97734d5 100644 --- a/README.md +++ b/README.md @@ -139,7 +139,7 @@ Initializing an API client is really easy: class MyApiClient # Arbitrary example def self.api - @api ||= Frenetic.new( url:'http://example.com/api' ) + @api ||= Frenetic.new(url:'http://example.com/api') end end ``` @@ -152,7 +152,7 @@ At the bare minimum, Frenetic only needs to know what the URL of your API is. Configuring Frenetic can be done during instantiation: ```ruby -Frenetic.new( url:'http://example.com', api_token:'123bada55k3y' ) +Frenetic.new(url:'http://example.com', api_token:'123bada55k3y') ``` Or with a block: @@ -168,7 +168,7 @@ end Or both... ```ruby -f = Frenetic.new( url:'http://example.com' ) +f = Frenetic.new(url:'http://example.com') f.configure do |cfg| cfg.api_token = '123bada55key' end @@ -184,13 +184,13 @@ middleware. To use Basic Auth, simply configure Frenetic with a `username` and `password`: ```ruby -Frenetic.new( url:url, username:'user', password:'password' ) +Frenetic.new(url:url, username:'user', password:'password') ``` If your API uses an App ID and API Key pair, you can pass those as well: ```ruby -Frenetic.new( url:url, app_id:'123abcSHA1', api_key:'bada55SHA1k3y' ) +Frenetic.new(url:url, app_id:'123abcSHA1', api_key:'bada55SHA1k3y') ``` The `app_id` and `api_key` values are simply aliases to `username` and @@ -201,7 +201,7 @@ The `app_id` and `api_key` values are simply aliases to `username` and To use Token Auth, simply configure Frenetic with your token: ```ruby -Frenetic.new( url:url, api_token:'bada55SHA1t0k3n' ) +Frenetic.new(url:url, api_token:'bada55SHA1t0k3n') ``` @@ -214,7 +214,7 @@ If configured to do so, Frenetic will autotmatically cache API responses. ##### Rack::Cache ```ruby -Frenetic.new( url:url, cache: :rack ) +Frenetic.new(url:url, cache: :rack) ``` Passing in a cache option of `:rack` will cause Frenetic to use Faraday's @@ -246,14 +246,14 @@ By default, Frenetic is configured to use Faraday's default adapter (usually Net::HTTP). You can change this with the `adapter` option: ```ruby -Frenetic.new( url:url, adapter: :patron ) +Frenetic.new(url:url, adapter: :patron) ``` Frenetic accepts any of the [Faraday adapter shortcuts][adapters], or an instance of the adapter itself: ```ruby -Frenetic.new( url:url, adapter:Faraday::Adapter::Patron ) +Frenetic.new(url:url, adapter:Faraday::Adapter::Patron) ``` @@ -263,7 +263,7 @@ If you have no control over the API, you can explicitly tell Frenetic how long to cache the API description for: ```ruby -Frenetic.new( url:url, default_root_cache_age:1.hour ) +Frenetic.new(url:url, default_root_cache_age:1.hour) ``` @@ -273,7 +273,7 @@ Frenetic.new( url:url, default_root_cache_age:1.hour ) Frenetic will yield its internal Faraday connection during initialization: ```ruby -Frenetic.new( url:url ) do |builder| +Frenetic.new(url:url) do |builder| # `builder` is the Faraday Connection instance with which you can # add additional Faraday Middlewares or tweak the configuration. end @@ -293,7 +293,7 @@ A Frenetic instance supports any HTTP verb that [Faraday][faraday] has impletented. This includes GET, POST, PUT, PATCH, and DELETE. ```ruby -api = Frenetic.new( url:url ) +api = Frenetic.new(url:url) api.get '/my_things/1' # { 'id' => 1, 'name' => 'My Thing', '_links' => { 'self' { 'href' => '/api/my_things/1' } } } @@ -314,8 +314,8 @@ class Order < Frenetic::Resource api_client { MyAPI } # TODO: Write a better example for this. - def self.find_all_by_name( name ) - api.get( search_url(name) ) and response.success? + def self.find_all_by_name(name) + api.get(search_url(name)) and response.success? end end ``` @@ -411,7 +411,7 @@ stub out all of the HTTP requests with something like WebMock or VCR, or you can use Frenetic in `test_mode` ```ruby -Frenetic.new( url:url, test_mode:true ) +Frenetic.new(url:url, test_mode:true) # ...or... api = Frenetic.new(url:url) api.config.test_mode = true diff --git a/Rakefile b/Rakefile index f57ae68..61b0338 100644 --- a/Rakefile +++ b/Rakefile @@ -1,2 +1,2 @@ #!/usr/bin/env rake -require "bundler/gem_tasks" +require 'bundler/gem_tasks' diff --git a/lib/frenetic.rb b/lib/frenetic.rb index 94cf244..ac01761 100644 --- a/lib/frenetic.rb +++ b/lib/frenetic.rb @@ -17,6 +17,8 @@ class Frenetic include ActiveSupport::Configurable include BrieflyMemoizable + MaxAge = /max-age=(?\d+)/ + config_accessor :adapter config_accessor :api_token config_accessor :cache @@ -49,12 +51,12 @@ class Frenetic url: nil, username: nil } - self.config.merge!(@@defaults) + config.merge!(@@defaults) # PENDING: [ActiveSupport4] Remove merge with class defaults def initialize(cfg = {}) - self.config.merge!(cfg.reverse_merge(self.class.config)) - yield self.config if block_given? + config.merge!(cfg.reverse_merge(self.class.config)) + yield config if block_given? end def connection @@ -74,10 +76,10 @@ def configure # # If no Cache-Control header is returned, then the results are not memoized. def description - if response = get(config.url.to_s) and response.success? - @description_age = cache_control_age(response.headers) - response.body - end + response = get(config.url.to_s) + return unless response.success? + @description_age = cache_control_age(response.headers) + response.body end briefly_memoize :description @@ -92,11 +94,12 @@ def reset_connection! private def cache_control_age(headers) - if cache_age = headers['Cache-Control'] - age = cache_age.match(%r{max-age=(?\d+)})[:max_age] + cache_age = headers['Cache-Control'] + if cache_age + age = cache_age.match(MaxAge)[:max_age] Time.now + age.to_i else config.default_root_cache_age end end -end \ No newline at end of file +end diff --git a/lib/frenetic/briefly_memoizable.rb b/lib/frenetic/briefly_memoizable.rb index 083452a..ee56894 100644 --- a/lib/frenetic/briefly_memoizable.rb +++ b/lib/frenetic/briefly_memoizable.rb @@ -8,14 +8,15 @@ module BrieflyMemoizable extend ActiveSupport::Concern module ClassMethods - def briefly_memoize( symbol ) + def briefly_memoize(symbol) original_method = "_unmemoized_#{symbol}".to_sym - memoized_ivar = "@#{symbol}" - age_ivar = "@#{symbol}_age" + memoized_ivar = "@#{symbol}" + age_ivar = "@#{symbol}_age" - class_eval <<-EOS + # rubocop:disable Metrics/LineLength + class_eval <<-CODE if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type) - raise "Already memoized #{symbol}" # raise "Already memoized mime_type" + fail "Already memoized #{symbol}" # fail "Already memoized mime_type" end # end alias #{original_method} #{symbol} # alias _unmemoized_mime_type mime_type @@ -27,8 +28,9 @@ def #{symbol}(*args) # def m def reload_#{symbol}! # def reload_mime_type! #{memoized_ivar} = nil # @mime_type = nil end # end - EOS + CODE + # rubocop:enable Metrics/LineLength end end end -end \ No newline at end of file +end diff --git a/lib/frenetic/concerns/collection_rest_methods.rb b/lib/frenetic/concerns/collection_rest_methods.rb index 5b7f46e..3b1cfc0 100644 --- a/lib/frenetic/concerns/collection_rest_methods.rb +++ b/lib/frenetic/concerns/collection_rest_methods.rb @@ -4,10 +4,9 @@ class Frenetic module CollectionRestMethods extend ActiveSupport::Concern - def get( id ) - if response = api.get( member_url(id) ) and response.success? - @resource_class.new response.body - end + def get(id) + response = api.get(member_url(id)) + @resource_class.new(response.body) if response.success? end end -end \ No newline at end of file +end diff --git a/lib/frenetic/concerns/hal_linked.rb b/lib/frenetic/concerns/hal_linked.rb index fd25dff..3a66b12 100644 --- a/lib/frenetic/concerns/hal_linked.rb +++ b/lib/frenetic/concerns/hal_linked.rb @@ -10,10 +10,11 @@ def links @params['_links'] end - def member_url( params = {} ) + def member_url(params = {}) resource = @resource_type || self.class.to_s.demodulize.underscore - link = links[resource] || links['self'] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{resource}"} - HypermediaLinkSet.new( link ).href params + link = links[resource] || links['self'] + fail MissingResourceUrl.new(resource) if !link + HypermediaLinkSet.new(link).href params end module ClassMethods @@ -21,15 +22,17 @@ def links api.description['_links'] end - def member_url( params = {} ) - link = links[namespace] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{namespace}"} - HypermediaLinkSet.new( link ).href params + def member_url(params = {}) + link = links[namespace] + fail MissingResourceUrl.new(namespace) if !link + HypermediaLinkSet.new(link).href params end def collection_url - link = links[namespace.pluralize] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{namespace.pluralize}"} - HypermediaLinkSet.new( link ).href + link = links[namespace.pluralize] + fail MissingResourceUrl.new(namespace.pluralize) if !link + HypermediaLinkSet.new(link).href end end end -end \ No newline at end of file +end diff --git a/lib/frenetic/concerns/member_rest_methods.rb b/lib/frenetic/concerns/member_rest_methods.rb index 350a28c..2f6e500 100644 --- a/lib/frenetic/concerns/member_rest_methods.rb +++ b/lib/frenetic/concerns/member_rest_methods.rb @@ -5,21 +5,18 @@ module MemberRestMethods extend ActiveSupport::Concern module ClassMethods - def find( params ) - params = { id:params } unless params.is_a? Hash + def find(params) + params = { id:params } unless params.is_a?(Hash) return as_mock(params) if test_mode? - if response = api.get( member_url(params) ) and response.success? - new response.body - end + response = api.get(member_url(params)) + new(response.body) if response.success? end def all return [] if test_mode? - - if response = api.get( collection_url ) and response.success? - Frenetic::ResourceCollection.new self, response.body - end + response = api.get(collection_url) + Frenetic::ResourceCollection.new(self, response.body) if response.success? end end end -end \ No newline at end of file +end diff --git a/lib/frenetic/concerns/structured.rb b/lib/frenetic/concerns/structured.rb index 284726d..b598188 100644 --- a/lib/frenetic/concerns/structured.rb +++ b/lib/frenetic/concerns/structured.rb @@ -28,7 +28,7 @@ def fetch_structure def rebuild_structure! destroy_structure! @@signatures[struct_key] = signature - Struct.new( struct_key, *@attrs.keys ) + Struct.new(struct_key, *@attrs.keys) end def structure_expired? @@ -45,4 +45,4 @@ def destroy_structure! Struct.send :remove_const, struct_key end end -end \ No newline at end of file +end diff --git a/lib/frenetic/connection.rb b/lib/frenetic/connection.rb index 3e06135..25cbf69 100644 --- a/lib/frenetic/connection.rb +++ b/lib/frenetic/connection.rb @@ -29,18 +29,8 @@ def valid? def process_config(raw_cfg) @config = {}.merge(raw_cfg.to_hash) - @config[:url] = Addressable::URI.parse(raw_cfg[:url]) - if @config[:url] && @config[:url].port.nil? - @config[:url].port = @config[:url].inferred_port - end - cfgs = @config.inject({builder:{}, conn:{}}) do |conf, (k,v)| - if ConnectionConfigKeys.include?(k) - conf[:conn][k] = v - else - conf[:builder][k] = v - end - conf - end + @config[:url] = process_url_config(raw_cfg) + cfgs = process_config_options(@config) [ @builder_config = cfgs[:builder], @connection_config = cfgs[:conn] @@ -69,8 +59,25 @@ def configure_adapter(builder) private + def process_url_config(raw_cfg) + url = Addressable::URI.parse(raw_cfg[:url]) + return if !url + url.port = url.inferred_port if url.port.nil? + url + end + + def process_config_options(options) + options.each_with_object(builder:{}, conn:{}) do |(k, v), conf| + if ConnectionConfigKeys.include?(k) + conf[:conn][k] = v + else + conf[:builder][k] = v + end + end + end + def validate_configuration! - raise ConfigError.new(self) if !valid? + fail ConfigError.new(self) if !valid? end def use_basic_auth(builder) @@ -86,11 +93,9 @@ def use_rack_cache(builder) builder.use( FaradayMiddleware::RackCompatible, Rack::Cache::Context, - { - metastore: "file:tmp/rack/meta/#{cache_key}", - entitystore: "file:tmp/rack/body/#{cache_key}", - ignore_headers: %w{Authorization Set-Cookie X-Content-Digest} - } + metastore: "file:tmp/rack/meta/#{cache_key}", + entitystore: "file:tmp/rack/body/#{cache_key}", + ignore_headers: %w(Authorization Set-Cookie X-Content-Digest) ) end @@ -107,7 +112,7 @@ def require_lib(lib = nil, context = nil) lib ? require(lib) : yield rescue NameError, LoadError => err context ||= self - raise ConfigError, "Could not load required `#{lib}` dependency for #{context}: #{err.message}" + raise MissingDependency.new(lib, context, err) end end end diff --git a/lib/frenetic/errors.rb b/lib/frenetic/errors.rb index 00e7ed6..141d094 100644 --- a/lib/frenetic/errors.rb +++ b/lib/frenetic/errors.rb @@ -24,9 +24,74 @@ def message end end + class MissingDependency < ConfigError + def initialize(lib, context, err) + @lib, @context, @err = lib, context, err + super(message) + end + + def message + "Could not load required `#{@lib}` dependency for " \ + "#{@context} (#{@err.class}: #{@err.message})" + end + end + # Raised when there is a Hypermedia error HypermediaError = Class.new(Error) + # Raised when there is no _link entry for the desired resource + class MissingRelevantLink < HypermediaError + def initialize(tmpl_vars, link_set) + @tmpl_vars = tmpl_vars + @link_set = link_set + end + + def message + "Could not find a relevant link for the data provided.\n" \ + "Are any of the links missing the templated:true property?\n" \ + " Template Data: #{@tmpl_vars}\n" \ + " Link Set: #{@link_set.collect(&:as_json)}" + end + end + + # Raised when a Resource's GET Url is not included in the _links hash + class MissingResourceUrl < HypermediaError + def initialize(resource) + @resource = resource + super(message) + end + + def message + %("No Hypermedia GET Url found for the resource "#{@resource}") + end + end + + # Raised when there is no schema defined by the Api root for the given resource + class MissingSchemaDefinition < HypermediaError + def initialize(namespace) + @namespace = namespace + super(message) + end + + def message + %(Could not find schema definition for the resource "#{@namespace}") + end + end + + # Raised when an expanded URL template is passed the wrong number of arguments + class UnfulfilledLinkTemplate < HypermediaError + def initialize(template, data) + @template = template + @data = data + end + + def message + "The data provided could not satisfy the template requirements.\n" \ + " Template: #{@template.pattern}\n" \ + " Data: #{@data}" + end + end + # Raised when there is a Link Template error LinkTemplateError = Class.new(Error) @@ -52,7 +117,7 @@ def initialize(namespace, resource) def message "Mock resource not defined for `#{namespace}`." \ " Create a new class that inherits from `#{resource}` and mixin" \ - " `Frenetic::ResourceMockery` to define a mock." + ' `Frenetic::ResourceMockery` to define a mock.' end end @@ -109,4 +174,4 @@ def message @original_exception.message end end -end \ No newline at end of file +end diff --git a/lib/frenetic/hypermedia_link.rb b/lib/frenetic/hypermedia_link.rb index 393bbef..60512d1 100644 --- a/lib/frenetic/hypermedia_link.rb +++ b/lib/frenetic/hypermedia_link.rb @@ -3,35 +3,33 @@ class Frenetic class HypermediaLink - def initialize( link ) + def initialize(link) @link = link.with_indifferent_access end - def href( tmpl_data = {} ) + def href(tmpl_data = {}) if templated? - expand tmpl_data + expand(tmpl_data) else @link['href'] end end - alias :to_url :href + alias_method :to_url, :href def templated? return false unless hash? - @link['templated'] == true end - def expandable?( tmpl_data ) + def expandable?(tmpl_data) return false unless templated? - tmpl_data = normalize_data(tmpl_data) - - (template.variables & tmpl_data.keys.map(&:to_s)).size == template.variables.size + tmpl_dataset = template.variables & tmpl_data.keys.map(&:to_s) + tmpl_dataset.size == template.variables.size end def template - @template ||= Addressable::Template.new @link['href'] + @template ||= Addressable::Template.new(@link['href']) end def as_json @@ -44,31 +42,26 @@ def rel private - def expand( tmpl_data ) + def expand(tmpl_data) tmpl_data = normalize_data(tmpl_data) - - return template.expand( tmpl_data ).to_s if expandable? tmpl_data - - raise Frenetic::HypermediaError, - "The data provided could not satisfy the template requirements.\n" \ - " Template: #{template.pattern}\n" \ - " Data: #{tmpl_data}" + return template.expand(tmpl_data).to_s if expandable?(tmpl_data) + fail UnfulfilledLinkTemplate.new(template, tmpl_data) end def hash? - @link.is_a? Hash + @link.is_a?(Hash) end - def normalize_data( data ) - return data if data.is_a? Hash - + def normalize_data(data) + return data if data.is_a?(Hash) infer_template_values data end - def infer_template_values( data ) + def infer_template_values(data) key = template.variables.first - - { key => data } + { + key => data + } end end -end \ No newline at end of file +end diff --git a/lib/frenetic/hypermedia_link_set.rb b/lib/frenetic/hypermedia_link_set.rb index 6cd63bd..cbfaacf 100644 --- a/lib/frenetic/hypermedia_link_set.rb +++ b/lib/frenetic/hypermedia_link_set.rb @@ -5,7 +5,7 @@ class Frenetic class HypermediaLinkSet < Delegator - def initialize( link_set = [] ) + def initialize(link_set = []) link_set = [link_set] unless link_set.is_a? Array @link_set = link_set.map do |link| @@ -17,27 +17,24 @@ def initialize( link_set = [] ) end end - def href( tmpl_vars = {} ) + def href(tmpl_vars = {}) return @link_set.first.href if tmpl_vars.blank? - - link = find_relevant_link( tmpl_vars ) and link.href( tmpl_vars ) + link = find_relevant_link(tmpl_vars) + link && link.href(tmpl_vars) end - def []( relation ) - @link_set.find{ |link| link.rel == relation.to_s } + def [](relation) + @link_set.find { |link| link.rel == relation.to_s } end - def find_relevant_link( tmpl_vars ) - @link_set.find{ |link| link.expandable? tmpl_vars } or - raise Frenetic::HypermediaError, - "Could not find a relevant link for the data provided.\n" \ - "Are any of the links missing the templated:true property?\n" \ - " Template Data: #{tmpl_vars}\n" \ - " Link Set: #{@link_set.collect(&:as_json)}" + def find_relevant_link(tmpl_vars) + @link_set.find do |link| + link.expandable?(tmpl_vars) + end || fail(Frenetic::MissingRelevantLink.new(tmpl_vars, @link_set)) end def __getobj__ @link_set end end -end \ No newline at end of file +end diff --git a/lib/frenetic/middleware/hal_json.rb b/lib/frenetic/middleware/hal_json.rb index 2b8211a..a372e3c 100644 --- a/lib/frenetic/middleware/hal_json.rb +++ b/lib/frenetic/middleware/hal_json.rb @@ -3,13 +3,12 @@ class Frenetic module Middleware class HalJson < FaradayMiddleware::ParseJson - def process_response(env) super case env[:status] - when 500...599 then raise ServerError.new(env) - when 400...499 then raise ClientError.new(env) + when 500...599 then fail ServerError.new(env) + when 400...499 then fail ClientError.new(env) end rescue Faraday::Error::ParsingError => err case env[:status] @@ -23,4 +22,4 @@ def process_response(env) end Faraday::Response.register_middleware \ - hal_json:lambda { Frenetic::Middleware::HalJson } \ No newline at end of file + hal_json: -> { Frenetic::Middleware::HalJson } diff --git a/lib/frenetic/resource.rb b/lib/frenetic/resource.rb index 3ab4771..8d69a66 100644 --- a/lib/frenetic/resource.rb +++ b/lib/frenetic/resource.rb @@ -13,7 +13,7 @@ class Resource < Delegator include HalLinked include MemberRestMethods - def self.api_client( client = nil ) + def self.api_client(client = nil) if client @api_client = client elsif block_given? @@ -24,33 +24,37 @@ def self.api_client( client = nil ) @api_client end end + # Alias class method hack - def self.api; api_client; end + def self.api + api_client + end - def self.namespace( namespace = nil ) + def self.namespace(namespace = nil) if namespace @namespace = namespace.to_s elsif @namespace @namespace else - @namespace = self.to_s.demodulize.underscore + @namespace = to_s.demodulize.underscore end end def self.properties return mock_class.default_attributes if test_mode? - (api.schema[namespace]||{})['properties'] or raise HypermediaError, %Q{Could not find schema definition for the resource "#{namespace}"} + props = (api.schema[namespace] || {})['properties'] + props || fail(MissingSchemaDefinition.new(namespace)) end def self.mock_class - @mock_class or raise Frenetic::UndefinedResourceMock.new(namespace, self) + @mock_class || fail(Frenetic::UndefinedResourceMock.new(namespace, self)) end - def self.as_mock( params = {} ) + def self.as_mock(params = {}) mock_class.new params end - def initialize( p = {} ) + def initialize(p = {}) build_params p @attrs = {} @@ -66,11 +70,11 @@ def initialize( p = {} ) def api_client self.class.api_client end - alias :api :api_client + alias_method :api, :api_client def attributes @attributes ||= begin - @structure.each_pair.each_with_object({}) do |(k,v), attrs| + @structure.each_pair.each_with_object({}) do |(k, v), attrs| attrs[k.to_s] = v end end @@ -80,14 +84,14 @@ def __getobj__ @structure end - def __setobj__( obj ) + def __setobj__(obj) @attributes = nil @structure = obj end def inspect - attrs = attributes.collect do |k,v| + attrs = attributes.collect do |k, v| val = v.is_a?(String) ? "\"#{v}\"" : v || 'nil' "#{k}=#{val}" end.join(' ') @@ -99,33 +103,37 @@ def inspect "#{k}=#{val}" end.join(' ') - "#<#{self.class}:0x#{"%x" % self.object_id}" \ + "#<#{self.class}:0x#{format('%x', object_id)}" \ " #{attrs}" \ " #{ivars}" \ - ">" + '>' end private - def build_params( p ) + def build_params(p) @params = (p || {}).with_indifferent_access end def extract_embedded_resources class_namespace = self.class.to_s.deconstantize - @params.fetch('_embedded',{}).each do |k, attrs| + @params.fetch('_embedded', {}).each do |k, attrs| class_name = "#{class_namespace}::#{k.classify}" - klass = class_name.constantize rescue OpenStruct - @attrs[k] = if self.class.test_mode? && klass.respond_to?(:as_mock) - klass.as_mock(attrs) + klass = begin + class_name.constantize + rescue + OpenStruct + end + if self.class.test_mode? && klass.respond_to?(:as_mock) + @attrs[k] = klass.as_mock(attrs) else - klass.new(attrs) + @attrs[k] = klass.new(attrs) end end end def build_structure - @structure = structure.new( *@attrs.values ) + @structure = structure.new(*@attrs.values) end def namespace @@ -140,4 +148,4 @@ def self.test_mode? !api_client || api_client.config.test_mode end end -end \ No newline at end of file +end diff --git a/lib/frenetic/resource_collection.rb b/lib/frenetic/resource_collection.rb index 5e27ce3..f8e51eb 100644 --- a/lib/frenetic/resource_collection.rb +++ b/lib/frenetic/resource_collection.rb @@ -6,7 +6,7 @@ class ResourceCollection < Delegator include HalLinked include CollectionRestMethods - def initialize( resource, params = {} ) + def initialize(resource, params = {}) @resource_class = resource @resources = [] @params = params || {} @@ -43,7 +43,7 @@ def extract_resources! end def embedded_collection - @params.fetch('_embedded',{}).fetch(collection_key, []) + @params.fetch('_embedded', {}).fetch(collection_key, []) end end -end \ No newline at end of file +end diff --git a/lib/frenetic/resource_mockery.rb b/lib/frenetic/resource_mockery.rb index 80be404..8f46976 100644 --- a/lib/frenetic/resource_mockery.rb +++ b/lib/frenetic/resource_mockery.rb @@ -21,7 +21,7 @@ def attributes end def properties - @params.each_with_object({}) do |(k,v), props| + @params.each_with_object({}) do |(k, v), props| props[k] = v.class.to_s.underscore end end @@ -44,14 +44,14 @@ def default_attributes private - def build_params( p ) - raw_params = (p || {}).with_indifferent_access + def build_params(params) + raw_params = (params || {}).with_indifferent_access defaults = default_attributes.with_indifferent_access @params = defaults.deep_merge(raw_params) end def build_structure - @structure = OpenStruct.new( @attrs ) + @structure = OpenStruct.new(@attrs) end end -end \ No newline at end of file +end diff --git a/lib/frenetic/version.rb b/lib/frenetic/version.rb index 819ee34..aeb2a3c 100644 --- a/lib/frenetic/version.rb +++ b/lib/frenetic/version.rb @@ -1,3 +1,3 @@ class Frenetic VERSION = '1.0.0.alpha.1' -end \ No newline at end of file +end diff --git a/spec/briefly_memoizable_spec.rb b/spec/briefly_memoizable_spec.rb index 694f4d2..c919f16 100644 --- a/spec/briefly_memoizable_spec.rb +++ b/spec/briefly_memoizable_spec.rb @@ -58,4 +58,4 @@ def external_call end end end -end \ No newline at end of file +end diff --git a/spec/concerns/hal_linked_spec.rb b/spec/concerns/hal_linked_spec.rb index d162a0f..b8c1a14 100644 --- a/spec/concerns/hal_linked_spec.rb +++ b/spec/concerns/hal_linked_spec.rb @@ -21,7 +21,7 @@ let(:_links) do { - '_links' => { 'self' => { 'href' => '/api/self' }} + '_links' => { 'self' => { 'href' => '/api/self' } } } end @@ -65,7 +65,7 @@ context 'with an implied self link' do let(:_links) do { - '_links' => { 'self' => { 'href' => '/api/self' }} + '_links' => { 'self' => { 'href' => '/api/self' } } } end @@ -92,7 +92,7 @@ it 'processes the link' do expect_any_instance_of(Frenetic::HypermediaLinkSet) - .to receive(:href).with( params ).and_call_original + .to receive(:href).with(params).and_call_original subject end end @@ -106,7 +106,7 @@ before do allow(MyTempResource) .to receive(:namespace) - .and_return(Time.now.to_i.to_s) + .and_return(Time.now.to_i.to_s) end it 'raises an error' do @@ -122,4 +122,4 @@ end end end -end \ No newline at end of file +end diff --git a/spec/concerns/member_rest_methods_spec.rb b/spec/concerns/member_rest_methods_spec.rb index 011a001..377f54b 100644 --- a/spec/concerns/member_rest_methods_spec.rb +++ b/spec/concerns/member_rest_methods_spec.rb @@ -84,4 +84,4 @@ end end end -end \ No newline at end of file +end diff --git a/spec/concerns/structured_spec.rb b/spec/concerns/structured_spec.rb index 9e90e5c..d003f06 100644 --- a/spec/concerns/structured_spec.rb +++ b/spec/concerns/structured_spec.rb @@ -3,7 +3,7 @@ describe Frenetic::Structured do let(:my_temp_resource) do Class.new do - def initialize( attrs = {} ) + def initialize(attrs = {}) @attrs = attrs end end @@ -24,7 +24,7 @@ def initialize( attrs = {} ) after { instance.destroy_structure! } - subject(:instance) { MyTempResource.new( foo:'foo', bar:'bar' ) } + subject(:instance) { MyTempResource.new(foo:'foo', bar:'bar') } describe '#struct_key' do subject { super().struct_key } @@ -121,9 +121,10 @@ def initialize( attrs = {} ) before do allow(instance).to receive(:signature).and_return(new_sig) - described_class.class_variable_set '@@signatures', { + described_class.class_variable_set( + '@@signatures', 'MyTempResourceFreneticResourceStruct' => old_sig - } + ) end context 'with a fresh signature' do @@ -206,4 +207,4 @@ def initialize( attrs = {} ) end end end -end \ No newline at end of file +end diff --git a/spec/connection_spec.rb b/spec/connection_spec.rb index cd66775..e341f3c 100644 --- a/spec/connection_spec.rb +++ b/spec/connection_spec.rb @@ -18,7 +18,7 @@ let(:url) { nil } it 'raises an error' do - expect{subject}.to raise_error Frenetic::ConfigError, %r{Url must be present} + expect{subject}.to raise_error Frenetic::ConfigError, /Url must be present/ end end diff --git a/spec/fixtures/test_api_requests.rb b/spec/fixtures/test_api_requests.rb index 657c119..e6ebb09 100644 --- a/spec/fixtures/test_api_requests.rb +++ b/spec/fixtures/test_api_requests.rb @@ -1,78 +1,81 @@ require 'json' class HttpStubs - def initialize( rspec ) + def initialize(rspec) @rspec = rspec end def defaults { status: 200, - headers: { 'Content-Type'=>'application/json' }, + headers: { 'Content-Type' => 'application/json' }, body: {} } end - def response( params = {} ) - defs = defaults.dup + def response(params = {}) + defs = defaults.dup headers = params.delete :headers defs[:headers].merge! headers || {} - defs.merge( params ).tap do |p| + defs.merge(params).tap do |p| p[:body] = p[:body].to_json end end def api_html_response - @rspec.stub_request( :any, 'example.com/api' ) - .to_return response( body:'Non-JSON response', status:200 ) + @rspec.stub_request(:any, 'example.com/api') + .to_return response(body:'Non-JSON response', status:200) end - def api_server_error( type = :json ) + def api_server_error(type = :json) body = '500 Server Error' body = { 'error' => body }.to_json if type == :json - @rspec.stub_request( :any, 'example.com/api' ) - .to_return response( body:body, status:500 ) + @rspec.stub_request(:any, 'example.com/api') + .to_return response(body:body, status:500) end - def api_client_error( type = :json ) + def api_client_error(type = :json) body = '404 Not Found' body = { 'error' => body }.to_json if type == :json - @rspec.stub_request( :any, 'example.com/api' ) - .to_return defaults.merge( body:body, status:404 ) + @rspec.stub_request(:any, 'example.com/api') + .to_return defaults.merge(body:body, status:404) end def api_description - @rspec.stub_request( :any, 'example.com/api' ) - .to_return response( body:schema, headers:{ 'Cache-Control' => 'max-age=3600, public' } ) + @rspec.stub_request(:any, 'example.com/api') + .to_return response(body:schema, headers:{ 'Cache-Control' => 'max-age=3600, public' }) end def unknown_instance - @rspec.stub_request( :get, 'example.com/api/my_temp_resources/1' ) - .to_return response( body:{ 'error' => '404 Not Found' }, status:404 ) + @rspec.stub_request(:get, 'example.com/api/my_temp_resources/1') + .to_return response(body:{ 'error' => '404 Not Found' }, status:404) end def known_instance - @rspec.stub_request( :get, 'example.com/api/my_temp_resources/1' ) - .to_return response( body:{ 'name' => 'Resource Name' } ) + @rspec.stub_request(:get, 'example.com/api/my_temp_resources/1') + .to_return response(body:{ 'name' => 'Resource Name' }) end def known_resource - @rspec.stub_request( :get, 'example.com/api/my_temp_resources' ) - .to_return response( body:{ - '_embedded' => { - 'my_temp_resources' => [ - { 'name' => 'Resource Name' } - ] + @rspec.stub_request(:get, 'example.com/api/my_temp_resources') + .to_return response( + body: { + '_embedded' => { + 'my_temp_resources' => [ + { 'name' => 'Resource Name' } + ] + } } - } ) + ) end + # rubocop:disable Metrics/MethodLength def schema { _embedded: { @@ -110,10 +113,11 @@ def schema } } end + # rubocop:enable Metrics/MethodLength end RSpec.configure do |c| c.before :all do - @stubs = HttpStubs.new( self ) + @stubs = HttpStubs.new(self) end -end \ No newline at end of file +end diff --git a/spec/frenetic_spec.rb b/spec/frenetic_spec.rb index 392547f..725cdd9 100644 --- a/spec/frenetic_spec.rb +++ b/spec/frenetic_spec.rb @@ -17,7 +17,7 @@ expect(subject).to include headers:kind_of(Hash) expect(subject).to include middleware:[] expect(subject).to include :password - expect(subject).to include ssl:{verify:true} + expect(subject).to include ssl:{ verify:true } expect(subject).to include test_mode:false expect(subject).to include :url expect(subject).to include :username @@ -37,7 +37,7 @@ end describe '#configure' do - subject { instance.configure {|c| } } + subject { instance.configure {|c| c } } it 'resets the Connection' do prev_connection = instance.connection @@ -240,4 +240,4 @@ # expect(instance.connection).to have_received(:delete) # end # end -end \ No newline at end of file +end diff --git a/spec/hypermedia_link_set_spec.rb b/spec/hypermedia_link_set_spec.rb index 9699a18..cf78a44 100644 --- a/spec/hypermedia_link_set_spec.rb +++ b/spec/hypermedia_link_set_spec.rb @@ -93,7 +93,7 @@ context 'with multiple matching links' do let(:link_a) do - Frenetic::HypermediaLink.new( href:'/foo/{id}', templated:true ) + Frenetic::HypermediaLink.new(href:'/foo/{id}', templated:true) end let(:links) do @@ -126,7 +126,7 @@ subject { super()[rel] } let(:link_b) do - Frenetic::HypermediaLink.new( href:'/bar', rel:'bar' ) + Frenetic::HypermediaLink.new(href:'/bar', rel:'bar') end let(:links) do @@ -152,4 +152,4 @@ end end end -end \ No newline at end of file +end diff --git a/spec/hypermedia_link_spec.rb b/spec/hypermedia_link_spec.rb index e1e0879..6b06a8f 100644 --- a/spec/hypermedia_link_spec.rb +++ b/spec/hypermedia_link_spec.rb @@ -150,4 +150,4 @@ expect(subject).to eq 'foo' end end -end \ No newline at end of file +end diff --git a/spec/middleware/hal_json_spec.rb b/spec/middleware/hal_json_spec.rb index 5047210..49aefe5 100644 --- a/spec/middleware/hal_json_spec.rb +++ b/spec/middleware/hal_json_spec.rb @@ -16,9 +16,9 @@ def process(body, content_type = nil, options = {}, status = 200) let(:options) { Hash.new } let(:headers) { Hash.new } let(:middleware) do - described_class.new(lambda {|env| + described_class.new(lambda do |env| Faraday::Response.new(env) - }, options) + end, options) end it 'does not change nil body' do @@ -78,4 +78,4 @@ def process(body, content_type = nil, options = {}, status = 200) end end end -end \ No newline at end of file +end diff --git a/spec/resource_collection_spec.rb b/spec/resource_collection_spec.rb index c18217f..0fa930c 100644 --- a/spec/resource_collection_spec.rb +++ b/spec/resource_collection_spec.rb @@ -17,11 +17,10 @@ before do stub_const 'MyTempResource', my_temp_resource - @stubs.api_description end - let(:collection_response) { + let(:collection_response) do { '_embedded' => { 'my_temp_resources' => [ @@ -39,7 +38,7 @@ } } } - } + end subject(:instance) { described_class.new(MyTempResource, collection_response) } @@ -84,4 +83,4 @@ expect(subject).to be_an_instance_of MyTempResource end end -end \ No newline at end of file +end diff --git a/spec/resource_mockery_spec.rb b/spec/resource_mockery_spec.rb index 4627172..4da6574 100644 --- a/spec/resource_mockery_spec.rb +++ b/spec/resource_mockery_spec.rb @@ -76,7 +76,7 @@ def self.default_attributes subject { MyNamespace::MyMockedResource.default_attributes } it 'allows implementors to specify sane defaults' do - expect(subject).to eq Hash.new + expect(subject).to eq({}) end end @@ -86,7 +86,7 @@ def self.default_attributes subject { MyNamespace::MyMockedResource.new.default_attributes } it 'proxies to the class method' do - expect(subject).to eq Hash.new + expect(subject).to eq({}) end end -end \ No newline at end of file +end diff --git a/spec/resource_spec.rb b/spec/resource_spec.rb index 17316c5..d1b80c8 100644 --- a/spec/resource_spec.rb +++ b/spec/resource_spec.rb @@ -147,7 +147,7 @@ def configure_with_instance! end it 'raises an error' do - expect{subject}.to raise_error Frenetic::HypermediaError + expect{subject}.to raise_error Frenetic::MissingSchemaDefinition end end @@ -233,14 +233,14 @@ def self.default_attributes context 'and an embedded resource' do let(:args) do - super().merge({ + super().merge( '_embedded' => { 'embedded_resource' => { 'id' => 99, 'genus' => 'canine' } } - }) + ) end context 'that is of a known type' do @@ -275,7 +275,7 @@ def self.default_attributes let(:args) { { gender:'male' } } it 'does not create accessors' do - expect{ subject.gender }.to raise_error NoMethodError + expect{subject.gender}.to raise_error(NoMethodError) end it 'is accessible in @params' do @@ -305,7 +305,7 @@ def self.default_attributes subject { MyNamespace::MyTempResource.new(id:54, name:'me').attributes } it 'returns attributes of the resource' do - expect(subject).to eq({'id' => 54, 'name' => 'me'}) + expect(subject).to eq('id' => 54, 'name' => 'me') end end -end \ No newline at end of file +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f7d6d48..3118cf6 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -6,4 +6,4 @@ # Requires supporting ruby files with custom matchers and macros, etc, # in spec/support/ and its subdirectories. -Dir['./spec/support/**/*.rb'].each {|f| require f} \ No newline at end of file +Dir['./spec/support/**/*.rb'].each { |f| require(f) } diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb index 2e1e4ca..00d2edb 100644 --- a/spec/support/rspec.rb +++ b/spec/support/rspec.rb @@ -1,4 +1,4 @@ RSpec.configure do |config| config.filter_run focus:true config.run_all_when_everything_filtered = true -end \ No newline at end of file +end diff --git a/spec/support/timecop.rb b/spec/support/timecop.rb index 6f2ad64..cb435ae 100644 --- a/spec/support/timecop.rb +++ b/spec/support/timecop.rb @@ -1 +1 @@ -require 'timecop' \ No newline at end of file +require 'timecop' diff --git a/spec/support/webmock.rb b/spec/support/webmock.rb index e3bc4c4..274ead1 100644 --- a/spec/support/webmock.rb +++ b/spec/support/webmock.rb @@ -1,3 +1,3 @@ require 'webmock/rspec' -Dir[File.expand_path('../../fixtures/*.rb', __FILE__)].each { |f| require f } \ No newline at end of file +Dir[File.expand_path('../../fixtures/*.rb', __FILE__)].each { |f| require f }