diff --git a/.rubocop.yml b/.rubocop.yml index aa5db9c..bed6815 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -12,7 +12,6 @@ AllCops: TargetRailsVersion: 7.0 TargetRubyVersion: 3.0 Exclude: - - 'lib/**/*' - 'gemfiles/**/*' - 'vendor/bundle/**/*' - 'tmp/**/*' diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index e7b1f0d..5a52118 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -6,6 +6,174 @@ # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: leading, trailing +Layout/DotPosition: + Exclude: + - 'lib/hawk/model/association.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. +# SupportedHashRocketStyles: key, separator, table +# SupportedColonStyles: key, separator, table +# SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit +Layout/HashAlignment: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/collection.rb' + - 'lib/hawk/model/finder.rb' + - 'lib/hawk/model/schema.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: symmetrical, new_line, same_line +Layout/MultilineMethodCallBraceLayout: + Exclude: + - 'lib/hawk/model/collection.rb' + +# This cop supports safe autocorrection (--autocorrect). +Lint/AmbiguousOperator: + Exclude: + - 'lib/hawk/model/configurator.rb' + - 'lib/hawk/polyfills.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: AllowSafeAssignment. +Lint/AssignmentInCondition: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/model/lookup.rb' + +# Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches. +Lint/DuplicateBranch: + Exclude: + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +Lint/ElseLayout: + Exclude: + - 'lib/hawk/model/association.rb' + +# Configuration parameters: AllowedParentClasses. +Lint/MissingSuper: + Exclude: + - 'lib/hawk/model/collection.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowPercentLiteralArrayArgument. +Lint/RedundantSplatExpansion: + Exclude: + - 'lib/hawk/model/association.rb' + +Lint/ShadowingOuterLocalVariable: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/finder.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: strict, consistent +Lint/SymbolConversion: + Exclude: + - 'lib/hawk/model/association.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. +Lint/UnusedBlockArgument: + Exclude: + - 'lib/hawk/model/base.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods. +Lint/UnusedMethodArgument: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/model/schema/dsl.rb' + - 'lib/hawk/rake/utils.rb' + +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 40 + +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 171 + +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 10 + +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 28 + +# Configuration parameters: CountComments, CountAsOne. +Metrics/ModuleLength: + Max: 146 + +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 14 + +# Configuration parameters: ForbiddenDelimiters. +# ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$)) +Naming/HeredocDelimiterNaming: + Exclude: + - 'lib/hawk/rake/default_task.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyleForLeadingUnderscores. +# SupportedStylesForLeadingUnderscores: disallowed, required, optional +Naming/MemoizedInstanceVariableName: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/connection.rb' + - 'lib/hawk/model/finder.rb' + - 'lib/hawk/model/proxy.rb' + - 'lib/hawk/model/querying.rb' + +# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames. +# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to +Naming/MethodParameterName: + Exclude: + - 'lib/hawk/model/querying.rb' + +# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# ForbiddenPrefixes: is_, has_, have_ +# AllowedMethods: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'lib/hawk/model/association.rb' + +Performance/MethodObjectAsBlock: + Exclude: + - 'lib/hawk/http.rb' + +# This cop supports safe autocorrection (--autocorrect). +Performance/RedundantBlockCall: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/http/instrumentation.rb' + - 'lib/hawk/model/lookup.rb' + +# This cop supports safe autocorrection (--autocorrect). +Performance/RegexpMatch: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/schema.rb' + +# This cop supports safe autocorrection (--autocorrect). +Performance/StringIdentifierArgument: + Exclude: + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/schema.rb' + # Configuration parameters: IgnoredMetadata. RSpec/DescribeClass: Exclude: @@ -13,3 +181,332 @@ RSpec/DescribeClass: - 'spec/basic_operations_spec.rb' - 'spec/collections_spec.rb' - 'spec/namespacing_spec.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: strict, flexible +Rails/TimeZone: + Exclude: + - 'lib/hawk/model/schema.rb' + +Security/Eval: + Exclude: + - 'lib/hawk/model/pagination.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowOnlyRestArgument, UseAnonymousForwarding, RedundantRestArgumentNames, RedundantKeywordRestArgumentNames, RedundantBlockArgumentNames. +# RedundantRestArgumentNames: args, arguments +# RedundantKeywordRestArgumentNames: kwargs, options, opts +# RedundantBlockArgumentNames: blk, block, proc +Style/ArgumentsForwarding: + Exclude: + - 'lib/hawk/model/configurator.rb' + - 'lib/hawk/model/proxy.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods. +# SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces +# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object +# FunctionalMethods: let, let!, subject, watch +# AllowedMethods: lambda, proc, it +Style/BlockDelimiters: + Exclude: + - 'lib/hawk/model/base.rb' + - 'lib/hawk/model/configurator.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: is_a?, kind_of? +Style/ClassCheck: + Exclude: + - 'lib/hawk/model/proxy.rb' + +Style/ClassVars: + Exclude: + - 'lib/hawk/http/caching.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/ColonMethodCall: + Exclude: + - 'lib/hawk/http/instrumentation.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: Keywords, RequireColon. +# Keywords: TODO, FIXME, OPTIMIZE, HACK, REVIEW, NOTE +Style/CommentAnnotation: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/http/instrumentation.rb' + - 'lib/hawk/model/association.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/CommentedKeyword: + Exclude: + - 'lib/hawk/linker.rb' + - 'lib/hawk/model/schema.rb' + +Style/DocumentDynamicEvalDefinition: + Exclude: + - 'lib/hawk/linker.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/pagination.rb' + +# Configuration parameters: AllowedConstants. +Style/Documentation: + Enabled: false + +# This cop supports safe autocorrection (--autocorrect). +Style/EachWithObject: + Exclude: + - 'lib/hawk/http.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/EvalWithLocation: + Exclude: + - 'lib/hawk/linker.rb' + - 'lib/hawk/model/pagination.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowedVars. +Style/FetchEnvVar: + Exclude: + - 'lib/hawk/rake/default_task.rb' + - 'lib/hawk/rake/utils.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: format, sprintf, percent +Style/FormatString: + Exclude: + - 'lib/hawk/http/instrumentation.rb' + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: MaxUnannotatedPlaceholdersAllowed, AllowedMethods, AllowedPatterns. +# SupportedStyles: annotated, template, unannotated +# AllowedMethods: redirect +Style/FormatStringToken: + EnforcedStyle: unannotated + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: always, always_true, never +Style/FrozenStringLiteralComment: + Enabled: false + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: MinBodyLength, AllowConsecutiveConditionals. +Style/GuardClause: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/lookup.rb' + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/polyfills.rb' + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/IfUnlessModifier: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/http/instrumentation.rb' + - 'lib/hawk/model/active.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/connection.rb' + - 'lib/hawk/model/finder.rb' + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/model/scoping.rb' + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/IfWithSemicolon: + Exclude: + - 'lib/hawk/model/association.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: line_count_dependent, lambda, literal +Style/Lambda: + Exclude: + - 'lib/hawk/model/association.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline +Style/MethodDefParentheses: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/association.rb' + +Style/MissingRespondToMissing: + Exclude: + - 'lib/hawk/model/proxy.rb' + - 'lib/hawk/model/schema/dsl.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle, Autocorrect. +# SupportedStyles: module_function, extend_self, forbidden +Style/ModuleFunction: + Exclude: + - 'lib/hawk/rake/utils.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: literals, strict +Style/MutableConstant: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/version.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns. +# SupportedStyles: predicate, comparison +Style/NumericPredicate: + Exclude: + - 'lib/hawk/http/instrumentation.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/pagination.rb' + - 'lib/hawk/model/proxy.rb' + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/rake/default_task.rb' + +# Configuration parameters: AllowedMethods. +# AllowedMethods: respond_to_missing? +Style/OptionalBooleanParameter: + Exclude: + - 'lib/hawk/model/proxy.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/ParallelAssignment: + Exclude: + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/rake/utils.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: PreferredDelimiters. +Style/PercentLiteralDelimiters: + Exclude: + - 'lib/hawk/http.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, AllowedCompactTypes. +# SupportedStyles: compact, exploded +Style/RaiseArgs: + Exclude: + - 'lib/hawk/model/querying.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantException: + Exclude: + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantParentheses: + Exclude: + - 'lib/hawk/model/finder.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowMultipleReturnValues. +Style/RedundantReturn: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/model/connection.rb' + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/RedundantSelf: + Exclude: + - 'lib/hawk/model/active.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/collection.rb' + - 'lib/hawk/model/connection.rb' + - 'lib/hawk/model/finder.rb' + - 'lib/hawk/model/schema.rb' + - 'lib/hawk/model/scoping.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/RedundantSelfAssignment: + Exclude: + - 'lib/hawk/model/proxy.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, AllowInnerSlashes. +# SupportedStyles: slashes, percent_r, mixed +Style/RegexpLiteral: + Exclude: + - 'lib/hawk/http.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/RescueModifier: + Exclude: + - 'lib/hawk/http.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle. +# SupportedStyles: implicit, explicit +Style/RescueStandardError: + Exclude: + - 'lib/hawk/model/schema.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: ConvertCodeThatCanStartToReturnNil, AllowedMethods, MaxChainLength. +# AllowedMethods: present?, blank?, presence, try, try! +Style/SafeNavigation: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/active.rb' + +# This cop supports safe autocorrection (--autocorrect). +Style/StderrPuts: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/rake/default_task.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline. +# SupportedStyles: single_quotes, double_quotes +Style/StringLiterals: + Exclude: + - 'lib/hawk/http/caching.rb' + - 'lib/hawk/model/collection.rb' + - 'lib/hawk/model/connection.rb' + - 'lib/hawk/rake/default_task.rb' + - 'lib/hawk/version.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: MinSize. +# SupportedStyles: percent, brackets +Style/SymbolArray: + EnforcedStyle: brackets + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInArrayLiteral: + Exclude: + - 'lib/hawk/model/schema.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: EnforcedStyleForMultiline. +# SupportedStylesForMultiline: comma, consistent_comma, no_comma +Style/TrailingCommaInHashLiteral: + Exclude: + - 'lib/hawk/http.rb' + - 'lib/hawk/model/schema.rb' + +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, AllowedMethods. +# AllowedMethods: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym +Style/TrivialAccessors: + Exclude: + - 'lib/hawk/model/collection.rb' + +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/ZeroLengthPredicate: + Exclude: + - 'lib/hawk/http/instrumentation.rb' + - 'lib/hawk/model/association.rb' + - 'lib/hawk/model/schema.rb' diff --git a/lib/hawk/error.rb b/lib/hawk/error.rb index f6bfc69..96edf8a 100644 --- a/lib/hawk/error.rb +++ b/lib/hawk/error.rb @@ -1,10 +1,8 @@ module Hawk - ## # Represents an error. # class Error < StandardError - # Usage error # class Configuration < self @@ -64,5 +62,4 @@ def initialize(message) end end end - end diff --git a/lib/hawk/http.rb b/lib/hawk/http.rb index bb69a62..e27e77b 100644 --- a/lib/hawk/http.rb +++ b/lib/hawk/http.rb @@ -1,5 +1,4 @@ module Hawk - require 'uri' require 'typhoeus' require 'multi_json' @@ -11,7 +10,6 @@ module Hawk # Represent an HTTP connector, to be linked to a {Model}. # class HTTP - prepend Caching include Instrumentation @@ -27,9 +25,9 @@ def initialize(base, options = {}) @defaults = DEFAULTS.deep_merge(options) @base = URI.parse(base).tap do |url| - unless %w( http https ).include? url.scheme + unless %w(http https).include? url.scheme raise Error::Configuration, - "URL '#{url}' is not valid: only http and https schemes are supported" + "URL '#{url}' is not valid: only http and https schemes are supported" end url.path += '/' unless url.path =~ /\/$/ @@ -46,6 +44,7 @@ def inspect def get(path, params = {}) parse raw_get(path, params) end + def raw_get(path, params = {}) request('GET', path, params) end @@ -53,6 +52,7 @@ def raw_get(path, params = {}) def post(path, params = {}) parse raw_post(path, params) end + def raw_post(path, params = {}) request('POST', path, params) end @@ -60,6 +60,7 @@ def raw_post(path, params = {}) def put(path, params = {}) parse raw_put(path, params) end + def raw_put(path, params = {}) request('PUT', path, params) end @@ -67,6 +68,7 @@ def raw_put(path, params = {}) def patch(path, params = {}) parse raw_patch(path, params) end + def raw_patch(path, params = {}) request('PATCH', path, params) end @@ -74,159 +76,161 @@ def raw_patch(path, params = {}) def delete(path, params = {}) parse raw_delete(path, params) end + def raw_delete(path, params = {}) request('DELETE', path, params) end - def url_length(path, method=:get, options={}) + def url_length(path, method = :get, options = {}) url = build_url(path) request = build_request_options_from(method.to_s.upcase, options) Typhoeus::Request.new(url, typhoeus_defaults.merge(options_for_typhoeus(request))).url.length end protected - def parse(body) - MultiJson.load(body) - end - def request(method, path, options) - url = build_url(path) - cache_opts = options.delete(:cache) || {} - request = build_request_options_from(method, options) - descriptor = { url: url, method: method, params: request[:params] } + def parse(body) + MultiJson.load(body) + end - instrument :request, descriptor do |descriptor| - caching descriptor.update(cache_opts) do - request = Typhoeus::Request.new(url, typhoeus_defaults.merge(options_for_typhoeus(request))) - request.on_complete(&method(:response_handler)) + def request(method, path, options) + url = build_url(path) + cache_opts = options.delete(:cache) || {} + request = build_request_options_from(method, options) + descriptor = { url: url, method: method, params: request[:params] } - request.run.body - end + instrument :request, descriptor do |descriptor| + caching descriptor.update(cache_opts) do + request = Typhoeus::Request.new(url, typhoeus_defaults.merge(options_for_typhoeus(request))) + request.on_complete(&method(:response_handler)) + + request.run.body end end + end private - def build_url path - base.merge(path.sub(/^\//, '')).to_s - end - def response_handler(response) - return if response.success? + def build_url path + base.merge(path.sub(/^\//, '')).to_s + end - req = response.request - url = req.url - meth = req.options.fetch(:method).to_s.upcase - it = [meth, url].join(' ') + def response_handler(response) + return if response.success? - if response.timed_out? - what, secs = if response.connect_time && response.connect_time.zero? - # Connect failed - [ :connect, req.options[:connecttimeout] ] - else - [ :request, req.options[:timeout] ] - end + req = response.request + url = req.url + meth = req.options.fetch(:method).to_s.upcase + it = [meth, url].join(' ') - raise Error::Timeout, "#{it}: #{what} timed out after #{secs} seconds" - end + if response.timed_out? + what, secs = if response.connect_time && response.connect_time.zero? + # Connect failed + [:connect, req.options[:connecttimeout]] + else + [:request, req.options[:timeout]] + end - case (code = response.response_code) - when 0 - raise Error::Empty, "#{it}: Empty response from server (#{response.status_message})" - when 400 - raise Error::BadRequest, "#{it} was a bad request" - when 403 - raise Error::Forbidden, "#{it} denied access" - when 404 - raise Error::NotFound, "#{it} was not found" - when 500 - raise Error::InternalServerError, "#{it}: Server error (#{response.body[0 .. 120]})" - else - app_error = parse_app_error_from(response.body) + raise Error::Timeout, "#{it}: #{what} timed out after #{secs} seconds" + end - raise Error::HTTP.new(code, "#{it} failed with error #{code} (#{response.status_message}): #{app_error}") - end + case (code = response.response_code) + when 0 + raise Error::Empty, "#{it}: Empty response from server (#{response.status_message})" + when 400 + raise Error::BadRequest, "#{it} was a bad request" + when 403 + raise Error::Forbidden, "#{it} denied access" + when 404 + raise Error::NotFound, "#{it} was not found" + when 500 + raise Error::InternalServerError, "#{it}: Server error (#{response.body[0..120]})" + else + app_error = parse_app_error_from(response.body) + + raise Error::HTTP.new(code, "#{it} failed with error #{code} (#{response.status_message}): #{app_error}") end + end - def parse_app_error_from(body) - if body[0] == '{' && body[-1] == '}' - resp = MultiJson.load(body) rescue nil - if resp.respond_to?(:key?) && resp.key?('error') - resp = resp.fetch('error') - end - resp - else - body[0..120] + def parse_app_error_from(body) + if body[0] == '{' && body[-1] == '}' + resp = MultiJson.load(body) rescue nil + if resp.respond_to?(:key?) && resp.key?('error') + resp = resp.fetch('error') end + resp + else + body[0..120] end + end - def build_request_options_from(method, options) - options = options.dup + def build_request_options_from(method, options) + options = options.dup - {}.tap do |request| - request[:method] = method + {}.tap do |request| + request[:method] = method - if options.key?(:headers) - request[:headers] = options.delete(:headers) - end + if options.key?(:headers) + request[:headers] = options.delete(:headers) + end - if options.key?(:options) - request.update options.delete(:options).except(:endpoint) # FIXME SPAGHETTI - end + if options.key?(:options) + request.update options.delete(:options).except(:endpoint) # FIXME SPAGHETTI + end - options.each do |k, v| - if v.nil? - options.delete(k) - elsif v.respond_to?(:id) - options[k] = v.id - end + options.each do |k, v| + if v.nil? + options.delete(k) + elsif v.respond_to?(:id) + options[k] = v.id end + end - # URL-encoded only, for now. - # - case method - when 'POST', 'PUT', 'PATCH' - request[:headers] ||= {} - request[:headers]['Content-Type'] ||= 'application/x-www-form-urlencoded' - - request[:body] = options - when 'GET', 'DELETE' - request[:params] = options - else - raise Hawk::Error, "Invalid HTTP method: #{method}" - end + # URL-encoded only, for now. + # + case method + when 'POST', 'PUT', 'PATCH' + request[:headers] ||= {} + request[:headers]['Content-Type'] ||= 'application/x-www-form-urlencoded' + + request[:body] = options + when 'GET', 'DELETE' + request[:params] = options + else + raise Hawk::Error, "Invalid HTTP method: #{method}" end end + end - def typhoeus_defaults - @_typhoeus_defaults ||= options_for_typhoeus(defaults).freeze - end + def typhoeus_defaults + @_typhoeus_defaults ||= options_for_typhoeus(defaults).freeze + end + + def options_for_typhoeus(hawk_options) + hawk_options.inject({}) do |ret, (opt, val)| + case opt + when :request_timeout, :timeout + ret[:timeout] = val.to_i - def options_for_typhoeus(hawk_options) - hawk_options.inject({}) do |ret, (opt, val)| - case opt - when :request_timeout, :timeout - ret[:timeout] = val.to_i - - when :connect_timeout - ret[:connecttimeout] = val.to_i - - when :username then - unless hawk_options.key?(:password) - raise Error::Configuration, - "The 'username' option requires a corresponding 'password' option" - end - - ret[:userpwd] = [val, hawk_options.fetch(:password)].join(':') - else - # Pass it along directly. Not pretty, not a consistent interface, - # but it eases development for now. For sure it deserves a FIXME. - # - ret[opt] = val + when :connect_timeout + ret[:connecttimeout] = val.to_i + + when :username + unless hawk_options.key?(:password) + raise Error::Configuration, + "The 'username' option requires a corresponding 'password' option" end - ret + ret[:userpwd] = [val, hawk_options.fetch(:password)].join(':') + else + # Pass it along directly. Not pretty, not a consistent interface, + # but it eases development for now. For sure it deserves a FIXME. + # + ret[opt] = val end + + ret end end - + end end diff --git a/lib/hawk/http/caching.rb b/lib/hawk/http/caching.rb index 45901d1..201a879 100644 --- a/lib/hawk/http/caching.rb +++ b/lib/hawk/http/caching.rb @@ -2,9 +2,7 @@ module Hawk class HTTP - module Caching - DEFAULTS = { server: 'localhost:11211', namespace: 'hawk', @@ -22,10 +20,10 @@ def initialize(*) def inspect description = if cache_configured? - "cache: ON #{@_cache_server} v#{@_cache_version}" - else - "cache: OFF" - end + "cache: ON #{@_cache_server} v#{@_cache_version}" + else + "cache: OFF" + end super.sub(/>$/, ", #{description}>") end @@ -39,98 +37,99 @@ def cache_options end protected - def caching(descriptor, &block) - return block.call unless cache_configured? - result = try_cache(descriptor, &block) + def caching(descriptor, &block) + return block.call unless cache_configured? - if descriptor.key?(:invalidate) - invalidate(descriptor) - end + result = try_cache(descriptor, &block) - return result + if descriptor.key?(:invalidate) + invalidate(descriptor) end + return result + end + private - def cache_key(descriptor) - MultiJson.dump(descriptor) - end - def try_cache(descriptor, &block) - return block.call unless descriptor[:method] == 'GET' + def cache_key(descriptor) + MultiJson.dump(descriptor) + end - key = cache_key(descriptor) + def try_cache(descriptor, &block) + return block.call unless descriptor[:method] == 'GET' - cached = @_cache.get(key) - if cached - descriptor[:cached] = true - cached - else - ttl = descriptor[:expires_in] || - @_cache_options[:expires_in] + key = cache_key(descriptor) + + cached = @_cache.get(key) + if cached + descriptor[:cached] = true + cached + else + ttl = descriptor[:expires_in] || + @_cache_options[:expires_in] - block.call.tap do |cacheable| - #$stderr.puts "CACHE: store #{key} with ttl #{ttl}" - @_cache.set(key, cacheable, ttl) - end + block.call.tap do |cacheable| + # $stderr.puts "CACHE: store #{key} with ttl #{ttl}" + @_cache.set(key, cacheable, ttl) end end + end - def invalidate(descriptor, &block) - descriptor = descriptor.dup - descriptor[:method] = 'GET' - descriptor[:params] ||= {} + def invalidate(descriptor, &block) + descriptor = descriptor.dup + descriptor[:method] = 'GET' + descriptor[:params] ||= {} - paths = Array.wrap(descriptor.delete(:invalidate)) + paths = Array.wrap(descriptor.delete(:invalidate)) - paths.each do |path| - descriptor[:url] = build_url(path) + paths.each do |path| + descriptor[:url] = build_url(path) - key = cache_key(descriptor) + key = cache_key(descriptor) - #$stderr.puts "CACHE: delete #{key}" - @_cache.delete(key) - end + # $stderr.puts "CACHE: delete #{key}" + @_cache.delete(key) end + end - def initialize_cache(options) - return if options[:disabled] + def initialize_cache(options) + return if options[:disabled] - unless options.key?(:server) - raise Error::Configuration, "Cache server option is mandatory" - end + unless options.key?(:server) + raise Error::Configuration, "Cache server option is mandatory" + end - client, server, version = connect_cache(options) + client, server, version = connect_cache(options) - if client && server && version - @_cache = client - @_cache_server = server - @_cache_version = version - @_cache_options = options - end + if client && server && version + @_cache = client + @_cache_server = server + @_cache_version = version + @_cache_options = options end + end - def connect_cache(options) - static_options = options.dup - static_options.delete(:expires_in) + def connect_cache(options) + static_options = options.dup + static_options.delete(:expires_in) - cache_servers[static_options] ||= begin - server = options[:server] - client = Dalli::Client.new(server, static_options) + cache_servers[static_options] ||= begin + server = options[:server] + client = Dalli::Client.new(server, static_options) - if version = client.version.fetch(server, nil) - [client, server, version] - else - $stderr.puts "Hawk: can't connect to memcached server #{server}" - nil - end + if version = client.version.fetch(server, nil) + [client, server, version] + else + $stderr.puts "Hawk: can't connect to memcached server #{server}" + nil end end + end - def cache_servers - @@cache_servers ||= {} - end + def cache_servers + @@cache_servers ||= {} + end end - end end diff --git a/lib/hawk/http/instrumentation.rb b/lib/hawk/http/instrumentation.rb index ad962dc..ab9b66a 100644 --- a/lib/hawk/http/instrumentation.rb +++ b/lib/hawk/http/instrumentation.rb @@ -1,6 +1,5 @@ module Hawk class HTTP - module Instrumentation def self.included(base) # https://github.com/ifad/instrumenter @@ -30,7 +29,7 @@ def instrument(type, payload, &block) url = payload[:url].to_s if payload[:params] && payload[:params].size > 0 - url << '?' << payload[:params].inject('') {|s, (k,v)| s << [k, '=', v, '&'].join }.chomp('&') + url << '?' << payload[:params].inject('') { |s, (k, v)| s << [k, '=', v, '&'].join }.chomp('&') end $stderr.printf ">> \033[1mHawk #{type}: #{payload[:method]} %s (%.2fms), cache %s\033[0m\n" % [ @@ -44,6 +43,5 @@ def instrument(type, payload, &block) end end end - end end diff --git a/lib/hawk/linker.rb b/lib/hawk/linker.rb index f16897b..927bd58 100644 --- a/lib/hawk/linker.rb +++ b/lib/hawk/linker.rb @@ -1,5 +1,4 @@ module Hawk - # Allows adding to any Ruby object an accessor referencing an {Hawk::Model}. # # Example, assuming Bar is defined and Foo responds_to `bar_id`: @@ -27,19 +26,20 @@ def resource_accessor(entity, options = {}) # Let's start simple. end private - def _monomorphic_resource_accessor(entity, options) - klass = options[:class_name] || entity.to_s.camelize - key = options[:primary_key] || [entity, :id].join('_') - class_eval <<-RUBY, __FILE__, __LINE__ -1 # Getter + def _monomorphic_resource_accessor(entity, options) + klass = options[:class_name] || entity.to_s.camelize + key = options[:primary_key] || [entity, :id].join('_') + + class_eval <<-RUBY, __FILE__, __LINE__ - 1 # Getter def #{entity} return nil unless self.#{key}.present? @_#{entity} ||= #{respond_to?(:module_parent) ? module_parent : parent}::#{klass}.find(self.#{key}) end - RUBY + RUBY - class_eval <<-RUBY, __FILE__, __LINE__ -1 # Setter + class_eval <<-RUBY, __FILE__, __LINE__ - 1 # Setter def #{entity}=(object) return if object.blank? @@ -51,27 +51,27 @@ def #{entity}=(object) @_#{entity} = object end - RUBY + RUBY - class_eval <<-RUBY, __FILE__, __LINE__ -1 # Reloader + class_eval <<-RUBY, __FILE__, __LINE__ - 1 # Reloader def reload(*) super.tap { @_#{entity} = nil } end - RUBY - end + RUBY + end - def _polymorphic_resource_accessor(entity, options) - key = options[:as] || entity + def _polymorphic_resource_accessor(entity, options) + key = options[:as] || entity - class_eval <<-RUBY, __FILE__, __LINE__ -1 # Getter + class_eval <<-RUBY, __FILE__, __LINE__ - 1 # Getter def #{entity} return nil unless self.#{key}_id.present? && self.#{key}_type.present? @_#{entity} ||= self.#{key}_type.constantize.find(self.#{key}_id) end - RUBY + RUBY - class_eval <<-RUBY, __FILE__, __LINE__ -1 # Setter + class_eval <<-RUBY, __FILE__, __LINE__ - 1 # Setter def #{entity}=(object) return if object.blank? @@ -84,15 +84,14 @@ def #{entity}=(object) @_#{entity} = object end - RUBY + RUBY - class_eval <<-RUBY, __FILE__, __LINE__ -1 # Reloader + class_eval <<-RUBY, __FILE__, __LINE__ - 1 # Reloader def reload(*) super.tap { @_#{entity} = nil } end - RUBY - end + RUBY + end end end - end diff --git a/lib/hawk/model.rb b/lib/hawk/model.rb index 6b3d926..d5fb882 100644 --- a/lib/hawk/model.rb +++ b/lib/hawk/model.rb @@ -1,5 +1,4 @@ module Hawk - module Model autoload :Base, 'hawk/model/base' autoload :Schema, 'hawk/model/schema' @@ -15,5 +14,4 @@ module Model autoload :Scoping, 'hawk/model/scoping' autoload :Active, 'hawk/model/active' end - end diff --git a/lib/hawk/model/active.rb b/lib/hawk/model/active.rb index da4c886..bb00e98 100644 --- a/lib/hawk/model/active.rb +++ b/lib/hawk/model/active.rb @@ -2,9 +2,7 @@ module Hawk module Model - module Active - def self.included(base) base.instance_eval do extend ActiveModel::Naming @@ -67,9 +65,8 @@ def save end def persist! - connection.put(path_for(nil), self.attributes.merge(cache: {invalidate: path_for(nil)})) + connection.put(path_for(nil), self.attributes.merge(cache: { invalidate: path_for(nil) })) end end - end end diff --git a/lib/hawk/model/association.rb b/lib/hawk/model/association.rb index 1305fe9..6cc44f8 100644 --- a/lib/hawk/model/association.rb +++ b/lib/hawk/model/association.rb @@ -1,8 +1,6 @@ module Hawk module Model - module Association - # Initialize the associations registry # def self.included(base) @@ -21,50 +19,51 @@ def initialize(attributes = {}, params = {}) end private - def preload_associations(attributes, params, scope) - self.instance_exec(scope, attributes, &scope.preload_association) - end - def add_association_object(scope, name, repr) - associations = scope.associations + def preload_associations(attributes, params, scope) + self.instance_exec(scope, attributes, &scope.preload_association) + end - (type, options) = associations[name.to_sym] || - associations[name.pluralize.to_sym] || - associations[name.singularize.to_sym] - if type - target = scope.model_class_for(options.fetch(:class_name)) - result = target.instantiate_from(repr, params) + def add_association_object(scope, name, repr) + associations = scope.associations - if is_collection?(type) - add_to_association_collection name, result - else - set_association_value name, result - end + (type, options) = associations[name.to_sym] || + associations[name.pluralize.to_sym] || + associations[name.singularize.to_sym] + if type + target = scope.model_class_for(options.fetch(:class_name)) + result = target.instantiate_from(repr, params) + + if is_collection?(type) + add_to_association_collection name, result else - raise Hawk::Error, "Unhandled assocation: #{name}" + set_association_value name, result end + else + raise Hawk::Error, "Unhandled assocation: #{name}" end + end - def is_collection? type - [ :polymorphic_belongs_to, :has_many ].include? type - end + def is_collection? type + [:polymorphic_belongs_to, :has_many].include? type + end - def add_to_association_collection name, target - variable = "@_#{name}" - instance_variable_set(variable, Collection.new) unless instance_variable_defined?(variable) - collection = instance_variable_get(variable) - target.respond_to?(:each) ? collection.concat(target) : collection.push(target) - end + def add_to_association_collection name, target + variable = "@_#{name}" + instance_variable_set(variable, Collection.new) unless instance_variable_defined?(variable) + collection = instance_variable_get(variable) + target.respond_to?(:each) ? collection.concat(target) : collection.push(target) + end - def set_association_value name, target - instance_variable_set("@_#{name}", target) - end + def set_association_value name, target + instance_variable_set("@_#{name}", target) + end - def clean_inherited_params inherited, opts={} - rv = {}.deep_merge opts - rv[:options] = inherited[:options] if inherited && inherited[:options] - rv - end + def clean_inherited_params inherited, opts = {} + rv = {}.deep_merge opts + rv[:options] = inherited[:options] if inherited && inherited[:options] + rv + end module ClassMethods # Propagate associations to the subclasses on inheritance @@ -229,14 +228,14 @@ def _define_association(name, type, options) # The raw associations code # CODE = { - has_many: -> (entities, options) { + has_many: ->(entities, options) { klass, key, from, as = options.values_at(*[:class_name, :primary_key, :from, :as]) conditions = if as.present? - "'#{as}_id' => self.id, '#{as}_type' => '#{self.name}'" - else - "'#{key}' => self.id" - end + "'#{as}_id' => self.id, '#{as}_type' => '#{self.name}'" + else + "'#{key}' => self.id" + end class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{entities} @@ -250,14 +249,14 @@ def #{entities} RUBY }, - has_one: -> (entity, options) { + has_one: ->(entity, options) { klass, key, from, nested, as = options.values_at(*[:class_name, :primary_key, :from, :nested, :as]) conditions = if as.present? - "'#{as}_id' => self.id, '#{as}_type' => '#{self.name}'" - else - "'#{key}' => self.id" - end + "'#{as}_id' => self.id, '#{as}_type' => '#{self.name}'" + else + "'#{key}' => self.id" + end class_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{entity}! @@ -286,7 +285,7 @@ def #{entity} RUBY }, - monomorphic_belongs_to: -> (entity, options) { + monomorphic_belongs_to: ->(entity, options) { klass, key, params = options.values_at(*[:class_name, :primary_key, :params]) params ||= {} ivar = "@_#{entity}".intern @@ -297,14 +296,14 @@ def #{entity} return unless (id = self.attributes.fetch(key.to_s, nil)) instance = self.class.model_class_for(klass). - find(id, clean_inherited_params( self.params, params )) + find(id, clean_inherited_params(self.params, params)) instance_variable_set(ivar, instance) end end }, - polymorphic_belongs_to: -> (entity, options) { + polymorphic_belongs_to: ->(entity, options) { key = options.fetch(:as) class_eval <<-RUBY, __FILE__, __LINE__ + 1 @@ -322,6 +321,5 @@ def #{entity} }.freeze end end - end end diff --git a/lib/hawk/model/base.rb b/lib/hawk/model/base.rb index 859b306..aca7700 100644 --- a/lib/hawk/model/base.rb +++ b/lib/hawk/model/base.rb @@ -1,6 +1,5 @@ module Hawk module Model - ## # Represents a remote entity, wrapped into a model holding each property in # an instance variable, casting the JSON values to data types inferred from @@ -23,12 +22,11 @@ def initialize(attributes = {}, params = {}) end def inspect - attributes = schema.inject('') {|s, (k,v)| + attributes = schema.inject('') { |s, (k, v)| s << " #{k}=#{read_attribute(k).inspect}" } "#<#{self.class.name}#{attributes}>" end end - end end diff --git a/lib/hawk/model/collection.rb b/lib/hawk/model/collection.rb index 0d7d172..e945a95 100644 --- a/lib/hawk/model/collection.rb +++ b/lib/hawk/model/collection.rb @@ -1,6 +1,5 @@ module Hawk module Model - class Collection < Array def initialize(elements = [], options = {}) self.replace(elements) @@ -30,12 +29,11 @@ def count def map(&block) self.class.new(super, - total_count: @total_count, - limit: @limit_value, - offset: @offset_value - ) + total_count: @total_count, + limit: @limit_value, + offset: @offset_value + ) end end - end end diff --git a/lib/hawk/model/configurator.rb b/lib/hawk/model/configurator.rb index 9e67486..85c9dd5 100644 --- a/lib/hawk/model/configurator.rb +++ b/lib/hawk/model/configurator.rb @@ -1,15 +1,13 @@ module Hawk module Model - module Configurator - def self.included(base) base.extend ClassMethods end module ClassMethods def configure(&block) - ([ self ] + configurable).each do |model| + ([self] + configurable).each do |model| model.instance_eval &block end end @@ -17,19 +15,18 @@ def configure(&block) def inherited(subclass) super - (@_configurable||=[]) << subclass + (@_configurable ||= []) << subclass end protected def configurable - (@_configurable||=[]).inject(Set.new) {|s, klass| + (@_configurable ||= []).inject(Set.new) { |s, klass| s.add klass s.merge klass.configurable }.to_a end end end - end end diff --git a/lib/hawk/model/connection.rb b/lib/hawk/model/connection.rb index b527111..9b41a16 100644 --- a/lib/hawk/model/connection.rb +++ b/lib/hawk/model/connection.rb @@ -1,6 +1,5 @@ module Hawk module Model - ## # Fetches models from the remote HTTP endpoint. # @@ -29,6 +28,7 @@ module SharedMethods def get(component, params = {}) connection.get(path_for(component), params) end + def raw_get(component, params = {}) connection.raw_get(path_for(component), params) end @@ -36,6 +36,7 @@ def raw_get(component, params = {}) def post(component, params = {}) connection.post(path_for(component), params) end + def raw_post(component, params = {}) connection.raw_post(path_for(component), params) end @@ -43,6 +44,7 @@ def raw_post(component, params = {}) def put(component, params = {}) connection.put(path_for(component), params) end + def raw_put(component, params = {}) connection.raw_put(path_for(component), params) end @@ -50,6 +52,7 @@ def raw_put(component, params = {}) def patch(component, params = {}) connection.patch(path_for(component), params) end + def raw_patch(component, params = {}) connection.raw_patch(path_for(component), params) end @@ -57,6 +60,7 @@ def raw_patch(component, params = {}) def delete(component, params = {}) connection.delete(path_for(component), params) end + def raw_delete(component, params = {}) connection.raw_delete(path_for(component), params) end @@ -83,7 +87,7 @@ def connection def url(url = nil) @_url = url.dup.freeze if url - configurable.each {|model| model.url = @_url } + configurable.each { |model| model.url = @_url } return @_url end @@ -96,7 +100,7 @@ def http_options(options = nil) @_http_options = @_http_options.deep_merge(options.dup).freeze end - configurable.each {|model| model.http_options = @_http_options } + configurable.each { |model| model.http_options = @_http_options } return @_http_options end @@ -105,7 +109,7 @@ def http_options(options = nil) def client_name(name = nil) @_client_name = name.dup.freeze if name - configurable.each {|model| model.client_name = @_client_name } + configurable.each { |model| model.client_name = @_client_name } return @_client_name end @@ -120,6 +124,5 @@ def inherited(subclass) end end end - end end diff --git a/lib/hawk/model/finder.rb b/lib/hawk/model/finder.rb index 44c3d43..5d79090 100644 --- a/lib/hawk/model/finder.rb +++ b/lib/hawk/model/finder.rb @@ -1,8 +1,6 @@ module Hawk module Model - module Finder - def self.included(base) base.extend ClassMethods end @@ -31,18 +29,18 @@ def find_many(ids, params = {}) def all(params = {}) path = path_for(nil, params) - if connection.url_length(path,:get,params) > 2000 + if connection.url_length(path, :get, params) > 2000 path = path_for(batch_path, params) method = :post end - repr = connection.send(method||:get, path, params) + repr = connection.send(method || :get, path, params) instantiate_many(repr, params) end def count(params = {}) params = {} unless params.is_a?(Hash) path = path_for(count_path, params) - method = connection.url_length(path,:get,params) > 2000 ? :post : :get + method = connection.url_length(path, :get, params) > 2000 ? :post : :get repr = connection.send(method, path, params) repr.fetch(count_key).to_i end @@ -74,7 +72,7 @@ def instantiate_many(repr, params) total_count: total_count } - Collection.new(collection.map! {|repr| instantiate_one(repr, params) }, collection_options) + Collection.new(collection.map! { |repr| instantiate_one(repr, params) }, collection_options) end def instantiate_one(repr, params) @@ -142,6 +140,5 @@ def count_path(path = nil) end end end - end end diff --git a/lib/hawk/model/lookup.rb b/lib/hawk/model/lookup.rb index e6f33e0..efae5f8 100644 --- a/lib/hawk/model/lookup.rb +++ b/lib/hawk/model/lookup.rb @@ -1,8 +1,6 @@ module Hawk module Model - module Lookup - def self.included(base) base.extend ClassMethods end @@ -60,6 +58,7 @@ def model_class_for(name, scope: self) end private + def look_up_model_class(name, scope) if self_constant = look_up_constant_in(name, scope) return self_constant @@ -93,9 +92,7 @@ def look_up_constant_in(name, scope) def cached_model_class_for(name, scope, &block) @_class_cache[[name, scope.name]] ||= block.call end - end end - end end diff --git a/lib/hawk/model/pagination.rb b/lib/hawk/model/pagination.rb index fb953e4..1b004a4 100644 --- a/lib/hawk/model/pagination.rb +++ b/lib/hawk/model/pagination.rb @@ -1,10 +1,9 @@ module Hawk module Model - module Pagination module Common def current_page - limit_value == 0 ? 1 : (offset_value / limit_value)+1 + limit_value == 0 ? 1 : (offset_value / limit_value) + 1 end end @@ -34,6 +33,5 @@ def #{Kaminari.config.page_method_name}(num = nil) end end end - end end diff --git a/lib/hawk/model/proxy.rb b/lib/hawk/model/proxy.rb index 56c64e2..e0d7d0a 100644 --- a/lib/hawk/model/proxy.rb +++ b/lib/hawk/model/proxy.rb @@ -1,6 +1,5 @@ module Hawk module Model - class Proxy include Enumerable @@ -71,59 +70,60 @@ def each(*args, &block) all.each(*args, &block) end - def respond_to?(meth, include_all=false) + def respond_to?(meth, include_all = false) super || klass.respond_to?(meth, include_all) || result.respond_to?(meth, include_all) end protected - def method_missing(meth, *args, &block) - if klass.respond_to?(meth) - - method = klass.method(meth) - dsl_method = - if method.owner.respond_to?(:module_parents) - method.owner.module_parents.include?(Hawk::Model) - else - method.owner.parents.include?(Hawk::Model) - end - - # If the method accepts a variable number of parameters, and - # exactly one is missing, push the scoped params at the end. - if !dsl_method && (method.arity + args.size) == -1 - args = args.push params - - # If the method accepts a variable number of parameters, and - # the last provided one is an hash, merge the scoped params. - elsif method.arity < 0 && (method.arity + args.size == 0) && args.last.is_a?(Hash) - args[-1] = params.deep_merge(args[-1]) - end + def method_missing(meth, *args, &block) + if klass.respond_to?(meth) - retval = klass.public_send(meth, *args, &block) - if retval.kind_of?(Proxy) - merge(retval) + method = klass.method(meth) + dsl_method = + if method.owner.respond_to?(:module_parents) + method.owner.module_parents.include?(Hawk::Model) else - retval + method.owner.parents.include?(Hawk::Model) end - elsif result.respond_to?(meth) - result.public_send(meth, *args, &block) + + # If the method accepts a variable number of parameters, and + # exactly one is missing, push the scoped params at the end. + if !dsl_method && (method.arity + args.size) == -1 + args = args.push params + + # If the method accepts a variable number of parameters, and + # the last provided one is an hash, merge the scoped params. + elsif method.arity < 0 && (method.arity + args.size == 0) && args.last.is_a?(Hash) + args[-1] = params.deep_merge(args[-1]) + + end + + retval = klass.public_send(meth, *args, &block) + if retval.kind_of?(Proxy) + merge(retval) else - super + retval end + elsif result.respond_to?(meth) + result.public_send(meth, *args, &block) + else + super end + end private - def merge(other) - target = other.is_a?(Void) ? to_void : self - target.where(other.params) - end - def to_void - Void.new(klass, params) - end - end + def merge(other) + target = other.is_a?(Void) ? to_void : self + target.where(other.params) + end + def to_void + Void.new(klass, params) + end + end end end diff --git a/lib/hawk/model/querying.rb b/lib/hawk/model/querying.rb index 4564369..20d030e 100644 --- a/lib/hawk/model/querying.rb +++ b/lib/hawk/model/querying.rb @@ -1,8 +1,6 @@ module Hawk module Model - module Querying - def self.included(base) base.extend ClassMethods end @@ -83,6 +81,5 @@ def first!(params = {}) alias find_by! first! end end - end end diff --git a/lib/hawk/model/schema.rb b/lib/hawk/model/schema.rb index 4281b5b..d34e33e 100644 --- a/lib/hawk/model/schema.rb +++ b/lib/hawk/model/schema.rb @@ -1,6 +1,5 @@ module Hawk module Model - module Schema def self.included(base) base.extend ClassMethods @@ -31,31 +30,32 @@ def write_attribute(name, value) end private - def get_attribute(name) - instance_variable_get(['@', name].join) - end - def set_attribute(name, value) - instance_variable_set(['@', name].join, value) - end + def get_attribute(name) + instance_variable_get(['@', name].join) + end - def cast!(attributes) - schema(attributes).each do |key, caster| - next unless attributes.key?(key) + def set_attribute(name, value) + instance_variable_set(['@', name].join, value) + end - value = attributes.fetch(key, nil) - value = caster.call(value) if caster + def cast!(attributes) + schema(attributes).each do |key, caster| + next unless attributes.key?(key) - set_attribute key, value - end + value = attributes.fetch(key, nil) + value = caster.call(value) if caster + + set_attribute key, value end + end - def schema(attributes = nil) - if attributes && attributes.size > 0 && self.class.schema.nil? - self.class.define_schema_from(attributes) - end - self.class.schema || {} + def schema(attributes = nil) + if attributes && attributes.size > 0 && self.class.schema.nil? + self.class.define_schema_from(attributes) end + self.class.schema || {} + end autoload :DSL, 'hawk/model/schema/dsl' @@ -162,13 +162,13 @@ def to_s bools = Set.new(['1', 'true', 1, true]) CASTERS = [ - Caster.new(:integer, -> (value) { Integer(value) }), - Caster.new(:float, -> (value) { Float(value) }), - Caster.new(:datetime, -> (value) { Time.parse(value) }), - Caster.new(:date, -> (value) { Date.parse(value) }), - Caster.new(:bignum, -> (value) { BigDecimal(value) }), - Caster.new(:boolean, -> (value) { bools.include?(value) }), - ].inject({}) {|h, c| h.update(c.type => c) } + Caster.new(:integer, ->(value) { Integer(value) }), + Caster.new(:float, ->(value) { Float(value) }), + Caster.new(:datetime, ->(value) { Time.parse(value) }), + Caster.new(:date, ->(value) { Date.parse(value) }), + Caster.new(:bignum, ->(value) { BigDecimal(value) }), + Caster.new(:boolean, ->(value) { bools.include?(value) }), + ].inject({}) { |h, c| h.update(c.type => c) } ATTRIBUTE_CASTS = { /_(?:at|from|until|on)$/ => :datetime, @@ -177,6 +177,5 @@ def to_s /^is_/ => :boolean, } end - end end diff --git a/lib/hawk/model/schema/dsl.rb b/lib/hawk/model/schema/dsl.rb index f2e3185..4ffa1ec 100644 --- a/lib/hawk/model/schema/dsl.rb +++ b/lib/hawk/model/schema/dsl.rb @@ -1,14 +1,13 @@ module Hawk module Model module Schema - class DSL def self.eval(code, &block) new(code).each(&block) end def initialize(code) - @types = Hash.new {|h,k| h[k] = []} + @types = Hash.new { |h, k| h[k] = [] } instance_eval(&code) end @@ -21,7 +20,6 @@ def method_missing(meth, *args, &block) @types[meth] += args end end - end end end diff --git a/lib/hawk/model/scoping.rb b/lib/hawk/model/scoping.rb index a7388eb..e8616f1 100644 --- a/lib/hawk/model/scoping.rb +++ b/lib/hawk/model/scoping.rb @@ -1,6 +1,5 @@ module Hawk module Model - module Scoping def self.included(base) base.extend ClassMethods @@ -16,6 +15,5 @@ def scope(name, impl) end end end - end end diff --git a/lib/hawk/polyfills.rb b/lib/hawk/polyfills.rb index d244b06..bdad196 100644 --- a/lib/hawk/polyfills.rb +++ b/lib/hawk/polyfills.rb @@ -1,5 +1,4 @@ module Hawk - module Polyfills def self.polyfill(klass, method, &impl) unless klass.instance_methods.include?(method) @@ -13,5 +12,4 @@ def self.polyfill(klass, method, &impl) require 'hawk/polyfills/module' require 'hawk/polyfills/hash' end - end diff --git a/lib/hawk/rake.rb b/lib/hawk/rake.rb index 8e94db6..6ad96d4 100644 --- a/lib/hawk/rake.rb +++ b/lib/hawk/rake.rb @@ -1,5 +1,4 @@ module Hawk - ## # Namespace to all rake-related functionality. # @@ -7,5 +6,4 @@ module Rake autoload :Utils, 'hawk/rake/utils.rb' autoload :DefaultTask, 'hawk/rake/default_task.rb' end - end diff --git a/lib/hawk/rake/default_task.rb b/lib/hawk/rake/default_task.rb index 98e65fc..14d1197 100644 --- a/lib/hawk/rake/default_task.rb +++ b/lib/hawk/rake/default_task.rb @@ -1,6 +1,5 @@ module Hawk module Rake - ## # Defines the default Eaco rake task. It runs tests and generates the docs. # @@ -144,12 +143,12 @@ def with_appraisal(msg) # @return [String] # def fancy(msg) - <<-EOF -\033[0m -\033[1;32m>>> -\033[1;32m>>> HAWK: \033[1;37m#{msg} -\033[1;32m>>> -\033[0m + <<~EOF + \033[0m + \033[1;32m>>> + \033[1;32m>>> HAWK: \033[1;37m#{msg} + \033[1;32m>>> + \033[0m EOF end @@ -175,6 +174,5 @@ def running_in_ci? ENV["CI"] end end - end end diff --git a/lib/hawk/rake/utils.rb b/lib/hawk/rake/utils.rb index fea3b0d..802f406 100644 --- a/lib/hawk/rake/utils.rb +++ b/lib/hawk/rake/utils.rb @@ -1,6 +1,5 @@ module Hawk module Rake - ## # Assorted utilities. # @@ -33,6 +32,5 @@ def gemfile File.basename(gemfile, '.*') if gemfile end end - end end