frenetic 0.0.20.alpha.6 → 1.0.0.alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -1
  3. data/Appraisals +9 -0
  4. data/Gemfile +1 -1
  5. data/README.md +2 -2
  6. data/frenetic.gemspec +8 -5
  7. data/gemfiles/faraday_08.gemfile +10 -0
  8. data/gemfiles/faraday_08.gemfile.lock +77 -0
  9. data/gemfiles/faraday_09.gemfile +10 -0
  10. data/gemfiles/faraday_09.gemfile.lock +77 -0
  11. data/lib/frenetic.rb +57 -30
  12. data/lib/frenetic/briefly_memoizable.rb +34 -0
  13. data/lib/frenetic/concerns/collection_rest_methods.rb +1 -1
  14. data/lib/frenetic/concerns/hal_linked.rb +5 -35
  15. data/lib/frenetic/concerns/member_rest_methods.rb +0 -2
  16. data/lib/frenetic/concerns/structured.rb +0 -5
  17. data/lib/frenetic/connection.rb +110 -0
  18. data/lib/frenetic/errors.rb +112 -0
  19. data/lib/frenetic/hypermedia_link.rb +74 -0
  20. data/lib/frenetic/hypermedia_link_set.rb +43 -0
  21. data/lib/frenetic/middleware/hal_json.rb +9 -12
  22. data/lib/frenetic/resource.rb +22 -6
  23. data/lib/frenetic/resource_collection.rb +0 -1
  24. data/lib/frenetic/resource_mockery.rb +55 -1
  25. data/lib/frenetic/version.rb +1 -1
  26. data/spec/{concerns/breifly_memoizable_spec.rb → briefly_memoizable_spec.rb} +10 -18
  27. data/spec/concerns/hal_linked_spec.rb +49 -62
  28. data/spec/concerns/member_rest_methods_spec.rb +8 -10
  29. data/spec/concerns/structured_spec.rb +70 -75
  30. data/spec/connection_spec.rb +137 -0
  31. data/spec/fixtures/test_api_requests.rb +8 -2
  32. data/spec/frenetic_spec.rb +221 -133
  33. data/spec/hypermedia_link_set_spec.rb +155 -0
  34. data/spec/hypermedia_link_spec.rb +153 -0
  35. data/spec/middleware/hal_json_spec.rb +13 -15
  36. data/spec/resource_collection_spec.rb +17 -16
  37. data/spec/resource_mockery_spec.rb +69 -0
  38. data/spec/resource_spec.rb +110 -63
  39. data/spec/support/rspec.rb +0 -1
  40. metadata +88 -75
  41. data/lib/frenetic/concerns/briefly_memoizable.rb +0 -34
  42. data/lib/frenetic/concerns/configurable.rb +0 -59
  43. data/lib/frenetic/concerns/resource_mockery.rb +0 -48
  44. data/lib/frenetic/configuration.rb +0 -88
  45. data/spec/concerns/configurable_spec.rb +0 -50
  46. data/spec/concerns/resource_mockery_spec.rb +0 -56
  47. data/spec/configuration_spec.rb +0 -134
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cc9d5efbe7083a07d49bc6d57da6a9ad2125e37d
4
+ data.tar.gz: 1d08f15fa29717b07f6bf43d6e46e8acc0832244
5
+ SHA512:
6
+ metadata.gz: ce6cdbdf561f06c6b4b9120b0222e69f031ea316f634e97f70df742a9c4015344ad551b6b60d072e149014ddd537def35ab6bbe7fbbd11367116fe7482527522
7
+ data.tar.gz: d70ca28073717ee35679abca5ef8107372ee7f3acf138070cdc40f91ef6a2b00481ddf49c5c76b9c6e6fcc86104e258c2f5407588d7b6c4b78abc1cb7e25a0de
@@ -1 +1 @@
1
- 1.9.3-p374
1
+ 2.1.2
@@ -0,0 +1,9 @@
1
+ appraise 'faraday-08' do
2
+ gem 'faraday', '~> 0.8.0'
3
+ gem 'faraday_middleware', '~> 0.8.0'
4
+ end
5
+
6
+ appraise 'faraday-09' do
7
+ gem 'faraday', '~> 0.9.0'
8
+ gem 'faraday_middleware', '~> 0.9.0'
9
+ end
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  source 'https://rubygems.org'
2
- ruby '1.9.3'
2
+ ruby '2.1.2'
3
3
 
4
4
  # Specify your gem's dependencies in frenetic.gemspec
5
5
  gemspec
data/README.md CHANGED
@@ -176,7 +176,7 @@ end
176
176
 
177
177
  #### Authentication
178
178
 
179
- Frenetic supports both Basic Auth and Tokens Auth via the appropriate Faraday
179
+ Frenetic supports both Basic Auth and Token Auth via the appropriate Faraday
180
180
  middleware.
181
181
 
182
182
  ##### Basic Auth
@@ -457,4 +457,4 @@ ideas on how to support other Hypermedia formats like [Collection+JSON][coll_jso
457
457
  [root_cache]: #default-root-cache-age
458
458
  [adapters]: https://github.com/lostisland/faraday/blob/c26a060acdd9eae356409c2ca79f1c22f8263de9/lib/faraday/adapter.rb#L7-L17
459
459
  [rack_cache]: https://github.com/rtomayko/rack-cache
460
- [coll_json]: http://amundsen.com/media-types/collection/
460
+ [coll_json]: http://amundsen.com/media-types/collection/
@@ -14,15 +14,18 @@ Gem::Specification.new do |gem|
14
14
  gem.name = "frenetic"
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = Frenetic::VERSION
17
+ gem.required_ruby_version = '>= 1.9.3'
17
18
 
18
- gem.add_dependency 'faraday', '~> 0.8.7'
19
- gem.add_dependency 'faraday_middleware', '~> 0.9.0'
19
+ gem.add_dependency 'faraday', '>= 0.8'
20
+ gem.add_dependency 'faraday_middleware', '>= 0.8'
20
21
  gem.add_dependency 'activesupport', '>= 3'
21
22
  gem.add_dependency 'addressable', '~> 2.3.4'
22
23
 
23
24
  gem.add_development_dependency 'awesome_print'
24
- gem.add_development_dependency 'rspec', '~> 2.13.0'
25
+ gem.add_development_dependency 'rspec', '~> 3.0.0'
25
26
  gem.add_development_dependency 'rack-cache', '~> 1.2'
26
- gem.add_development_dependency 'webmock', '~> 1.11.0'
27
- gem.add_development_dependency 'timecop', '~> 0.6.1'
27
+ gem.add_development_dependency 'faraday-http-cache', '~> 0.4.2'
28
+ gem.add_development_dependency 'webmock', '~> 1.18.0'
29
+ gem.add_development_dependency 'timecop', '~> 0.7.1'
30
+ gem.add_development_dependency 'appraisal', '~> 1.0.2'
28
31
  end
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ ruby "2.1.2"
6
+
7
+ gem "faraday", "~> 0.8.0"
8
+ gem "faraday_middleware", "~> 0.8.0"
9
+
10
+ gemspec :path => "../"
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ frenetic (0.0.20.alpha.6)
5
+ activesupport (>= 3)
6
+ addressable (~> 2.3.4)
7
+ faraday (>= 0.8)
8
+ faraday_middleware (>= 0.8)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (4.1.5)
14
+ i18n (~> 0.6, >= 0.6.9)
15
+ json (~> 1.7, >= 1.7.7)
16
+ minitest (~> 5.1)
17
+ thread_safe (~> 0.1)
18
+ tzinfo (~> 1.1)
19
+ addressable (2.3.6)
20
+ appraisal (1.0.2)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ awesome_print (1.2.0)
25
+ crack (0.4.2)
26
+ safe_yaml (~> 1.0.0)
27
+ diff-lcs (1.2.5)
28
+ faraday (0.8.9)
29
+ multipart-post (~> 1.2.0)
30
+ faraday-http-cache (0.4.2)
31
+ faraday (~> 0.8)
32
+ faraday_middleware (0.8.8)
33
+ faraday (>= 0.7.4, < 0.9)
34
+ i18n (0.6.11)
35
+ json (1.8.1)
36
+ minitest (5.4.1)
37
+ multipart-post (1.2.0)
38
+ rack (1.5.2)
39
+ rack-cache (1.2)
40
+ rack (>= 0.4)
41
+ rake (10.3.2)
42
+ rspec (3.0.0)
43
+ rspec-core (~> 3.0.0)
44
+ rspec-expectations (~> 3.0.0)
45
+ rspec-mocks (~> 3.0.0)
46
+ rspec-core (3.0.4)
47
+ rspec-support (~> 3.0.0)
48
+ rspec-expectations (3.0.4)
49
+ diff-lcs (>= 1.2.0, < 2.0)
50
+ rspec-support (~> 3.0.0)
51
+ rspec-mocks (3.0.4)
52
+ rspec-support (~> 3.0.0)
53
+ rspec-support (3.0.4)
54
+ safe_yaml (1.0.3)
55
+ thor (0.19.1)
56
+ thread_safe (0.3.4)
57
+ timecop (0.7.1)
58
+ tzinfo (1.2.2)
59
+ thread_safe (~> 0.1)
60
+ webmock (1.18.0)
61
+ addressable (>= 2.3.6)
62
+ crack (>= 0.3.2)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ appraisal (~> 1.0.2)
69
+ awesome_print
70
+ faraday (~> 0.8.0)
71
+ faraday-http-cache (~> 0.4.2)
72
+ faraday_middleware (~> 0.8.0)
73
+ frenetic!
74
+ rack-cache (~> 1.2)
75
+ rspec (~> 3.0.0)
76
+ timecop (~> 0.7.1)
77
+ webmock (~> 1.18.0)
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ ruby "2.1.2"
6
+
7
+ gem "faraday", "~> 0.9.0"
8
+ gem "faraday_middleware", "~> 0.9.0"
9
+
10
+ gemspec :path => "../"
@@ -0,0 +1,77 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ frenetic (0.0.20.alpha.6)
5
+ activesupport (>= 3)
6
+ addressable (~> 2.3.4)
7
+ faraday (>= 0.8)
8
+ faraday_middleware (>= 0.8)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (4.1.5)
14
+ i18n (~> 0.6, >= 0.6.9)
15
+ json (~> 1.7, >= 1.7.7)
16
+ minitest (~> 5.1)
17
+ thread_safe (~> 0.1)
18
+ tzinfo (~> 1.1)
19
+ addressable (2.3.6)
20
+ appraisal (1.0.2)
21
+ bundler
22
+ rake
23
+ thor (>= 0.14.0)
24
+ awesome_print (1.2.0)
25
+ crack (0.4.2)
26
+ safe_yaml (~> 1.0.0)
27
+ diff-lcs (1.2.5)
28
+ faraday (0.9.0)
29
+ multipart-post (>= 1.2, < 3)
30
+ faraday-http-cache (0.4.2)
31
+ faraday (~> 0.8)
32
+ faraday_middleware (0.9.1)
33
+ faraday (>= 0.7.4, < 0.10)
34
+ i18n (0.6.11)
35
+ json (1.8.1)
36
+ minitest (5.4.1)
37
+ multipart-post (2.0.0)
38
+ rack (1.5.2)
39
+ rack-cache (1.2)
40
+ rack (>= 0.4)
41
+ rake (10.3.2)
42
+ rspec (3.0.0)
43
+ rspec-core (~> 3.0.0)
44
+ rspec-expectations (~> 3.0.0)
45
+ rspec-mocks (~> 3.0.0)
46
+ rspec-core (3.0.4)
47
+ rspec-support (~> 3.0.0)
48
+ rspec-expectations (3.0.4)
49
+ diff-lcs (>= 1.2.0, < 2.0)
50
+ rspec-support (~> 3.0.0)
51
+ rspec-mocks (3.0.4)
52
+ rspec-support (~> 3.0.0)
53
+ rspec-support (3.0.4)
54
+ safe_yaml (1.0.3)
55
+ thor (0.19.1)
56
+ thread_safe (0.3.4)
57
+ timecop (0.7.1)
58
+ tzinfo (1.2.2)
59
+ thread_safe (~> 0.1)
60
+ webmock (1.18.0)
61
+ addressable (>= 2.3.6)
62
+ crack (>= 0.3.2)
63
+
64
+ PLATFORMS
65
+ ruby
66
+
67
+ DEPENDENCIES
68
+ appraisal (~> 1.0.2)
69
+ awesome_print
70
+ faraday (~> 0.9.0)
71
+ faraday-http-cache (~> 0.4.2)
72
+ faraday_middleware (~> 0.9.0)
73
+ frenetic!
74
+ rack-cache (~> 1.2)
75
+ rspec (~> 3.0.0)
76
+ timecop (~> 0.7.1)
77
+ webmock (~> 1.18.0)
@@ -1,44 +1,69 @@
1
1
  require 'socket'
2
2
  require 'faraday'
3
3
  require 'faraday_middleware'
4
+ require 'active_support/configurable'
5
+ require 'active_support/core_ext/hash/reverse_merge'
4
6
 
5
7
  require 'frenetic/version'
6
- require 'frenetic/concerns/configurable'
7
- require 'frenetic/concerns/briefly_memoizable'
8
+ require 'frenetic/errors'
9
+ require 'frenetic/briefly_memoizable'
10
+ require 'frenetic/connection'
8
11
  require 'frenetic/middleware/hal_json'
9
12
  require 'frenetic/resource'
10
13
  require 'frenetic/resource_collection'
11
14
 
12
15
  class Frenetic
13
16
  extend Forwardable
14
- include Configurable
17
+ include ActiveSupport::Configurable
15
18
  include BrieflyMemoizable
16
19
 
17
- def_delegators :connection, :get, :put, :post, :delete
18
-
19
- Error = Class.new(StandardError)
20
- ConfigError = Class.new(Error)
21
- ClientError = Class.new(Error)
22
- ServerError = Class.new(Error)
23
- ParsingError = Class.new(Error)
24
- HypermediaError = Class.new(Error)
20
+ config_accessor :adapter
21
+ config_accessor :api_token
22
+ config_accessor :cache
23
+ config_accessor :default_root_cache_age
24
+ config_accessor :headers
25
+ config_accessor :middleware
26
+ config_accessor :password
27
+ config_accessor :ssl
28
+ config_accessor :test_mode
29
+ config_accessor :url
30
+ config_accessor :username
31
+
32
+ def_delegators :connection, :delete, :get, :head, :options, :patch, :post, :put
33
+
34
+ # Can't explicitly use config_accessor because we need defaults and
35
+ # ActiveSupport < 4 does not support them
36
+ @@defaults = {
37
+ adapter: Faraday.default_adapter,
38
+ api_token: nil,
39
+ cache: false,
40
+ default_root_cache_age: nil,
41
+ headers: {
42
+ accept: 'application/hal+json',
43
+ user_agent: "Frenetic v#{Frenetic::VERSION}; #{Socket.gethostname}"
44
+ },
45
+ middleware: [],
46
+ password: nil,
47
+ ssl: { verify:true },
48
+ test_mode: false,
49
+ url: nil,
50
+ username: nil
51
+ }
52
+ self.config.merge!(@@defaults)
53
+
54
+ # PENDING: [ActiveSupport4] Remove merge with class defaults
55
+ def initialize(cfg = {})
56
+ self.config.merge!(cfg.reverse_merge(self.class.config))
57
+ yield self.config if block_given?
58
+ end
25
59
 
26
60
  def connection
27
- @connection ||= begin
28
- validate_configuration!
29
-
30
- Faraday.new( config ) do |builder|
31
- configure_authentication builder
32
-
33
- builder.response :hal_json
34
-
35
- configure_caching builder
36
-
37
- @builder_config.call( builder ) if @builder_config
61
+ @connection ||= Connection.new(config)
62
+ end
38
63
 
39
- builder.adapter config.adapter
40
- end
41
- end
64
+ # PENDING: [ActiveSupport4] Use super.
65
+ def configure
66
+ yield(config).tap { reset_connection! }
42
67
  end
43
68
 
44
69
  # Since Frenetic needs to frequently refer to the API design, the result of
@@ -49,9 +74,8 @@ class Frenetic
49
74
  #
50
75
  # If no Cache-Control header is returned, then the results are not memoized.
51
76
  def description
52
- if response = get( config.url.to_s ) and response.success?
53
- @description_age = cache_control_age( response.headers )
54
-
77
+ if response = get(config.url.to_s) and response.success?
78
+ @description_age = cache_control_age(response.headers)
55
79
  response.body
56
80
  end
57
81
  end
@@ -61,12 +85,15 @@ class Frenetic
61
85
  description['_embedded']['schema']
62
86
  end
63
87
 
88
+ def reset_connection!
89
+ @connection = nil
90
+ end
91
+
64
92
  private
65
93
 
66
- def cache_control_age( headers )
94
+ def cache_control_age(headers)
67
95
  if cache_age = headers['Cache-Control']
68
96
  age = cache_age.match(%r{max-age=(?<max_age>\d+)})[:max_age]
69
-
70
97
  Time.now + age.to_i
71
98
  else
72
99
  config.default_root_cache_age
@@ -0,0 +1,34 @@
1
+ require 'active_support/concern'
2
+
3
+ # Memoizes method calls, but only for a specific period of time.
4
+ # Useful for supporting HTTP Cache-Control without an external caching layer
5
+ # like Rack::Cache
6
+ class Frenetic
7
+ module BrieflyMemoizable
8
+ extend ActiveSupport::Concern
9
+
10
+ module ClassMethods
11
+ def briefly_memoize( symbol )
12
+ original_method = "_unmemoized_#{symbol}".to_sym
13
+ memoized_ivar = "@#{symbol}"
14
+ age_ivar = "@#{symbol}_age"
15
+
16
+ class_eval <<-EOS
17
+ if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
18
+ raise "Already memoized #{symbol}" # raise "Already memoized mime_type"
19
+ end # end
20
+ alias #{original_method} #{symbol} # alias _unmemoized_mime_type mime_type
21
+
22
+ def #{symbol}(*args) # def mime_type(*args)
23
+ #{memoized_ivar} = nil if #{age_ivar} && Time.now > #{age_ivar} # @mime_type = nil if @mime_type_age && Time.now > @mime_type_age
24
+ #{memoized_ivar} ||= #{original_method}(*args) # @mime_type ||= _unmemoized_mime_type(*args)
25
+ end # end
26
+
27
+ def reload_#{symbol}! # def reload_mime_type!
28
+ #{memoized_ivar} = nil # @mime_type = nil
29
+ end # end
30
+ EOS
31
+ end
32
+ end
33
+ end
34
+ end
@@ -10,4 +10,4 @@ class Frenetic
10
10
  end
11
11
  end
12
12
  end
13
- end
13
+ end
@@ -1,5 +1,6 @@
1
1
  require 'active_support/concern'
2
- require 'addressable/template'
2
+
3
+ require 'frenetic/hypermedia_link_set'
3
4
 
4
5
  class Frenetic
5
6
  module HalLinked
@@ -11,10 +12,8 @@ class Frenetic
11
12
 
12
13
  def member_url( params = {} )
13
14
  resource = @resource_type || self.class.to_s.demodulize.underscore
14
-
15
15
  link = links[resource] || links['self'] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{resource}"}
16
-
17
- self.class.parse_link link, params
16
+ HypermediaLinkSet.new( link ).href params
18
17
  end
19
18
 
20
19
  module ClassMethods
@@ -24,42 +23,13 @@ class Frenetic
24
23
 
25
24
  def member_url( params = {} )
26
25
  link = links[namespace] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{namespace}"}
27
-
28
- parse_link link, params
26
+ HypermediaLinkSet.new( link ).href params
29
27
  end
30
28
 
31
29
  def collection_url
32
30
  link = links[namespace.pluralize] or raise HypermediaError, %Q{No Hypermedia GET Url found for the resource "#{namespace.pluralize}"}
33
-
34
- link['href']
35
- end
36
-
37
- def parse_link( link, params = {} )
38
- if link['templated']
39
- expand_link link, params
40
- else
41
- link['href']
42
- end
43
- end
44
-
45
- private
46
-
47
- def expand_link( link, params )
48
- tmpl = Addressable::Template.new link['href']
49
-
50
- if params && !params.is_a?(Hash)
51
- params = infer_url_template_values tmpl, params
52
- end
53
-
54
- tmpl.expand( params ).to_s
31
+ HypermediaLinkSet.new( link ).href
55
32
  end
56
-
57
- def infer_url_template_values( tmpl, params )
58
- key = tmpl.variables.first
59
-
60
- { key => params }
61
- end
62
-
63
33
  end
64
34
  end
65
35
  end