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

Sign up to get free protection for your applications and to get access to all the features.
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