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
@@ -1,34 +0,0 @@
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
- module BrieflyMemoizable
7
- extend ActiveSupport::Concern
8
-
9
- module ClassMethods
10
- def briefly_memoize( symbol )
11
- original_method = "_unmemoized_#{symbol}".to_sym
12
- memoized_ivar = "@#{symbol}"
13
- age_ivar = "@#{symbol}_age"
14
-
15
- class_eval <<-EOS
16
- if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
17
- raise "Already memoized #{symbol}" # raise "Already memoized mime_type"
18
- end # end
19
- alias #{original_method} #{symbol} # alias _unmemoized_mime_type mime_type
20
-
21
- def #{symbol}(*args) # def mime_type(*args)
22
- #{memoized_ivar} = nil if #{age_ivar} && Time.now > #{age_ivar} # @mime_type = nil if @mime_type_age && Time.now > @mime_type_age
23
- #
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
-
34
- end
@@ -1,59 +0,0 @@
1
- require 'active_support/configurable'
2
- require 'active_support/concern'
3
-
4
- require 'frenetic/configuration'
5
-
6
- class Frenetic
7
- module Configurable
8
- extend ActiveSupport::Concern
9
-
10
- included do
11
- include ActiveSupport::Configurable
12
- # Don't allow the class to be configured
13
- class << self
14
- undef :configure
15
- end
16
- end
17
-
18
- def initialize( cfg = {} )
19
- config.merge! Frenetic::Configuration.new(cfg).attributes
20
-
21
- @builder_config = Proc.new if block_given?
22
- end
23
-
24
- def configure
25
- yield config
26
- end
27
-
28
- private
29
-
30
- def validate_configuration!
31
- raise( ConfigError, 'A URL must be defined' ) unless config.url
32
- end
33
-
34
- def configure_authentication( builder )
35
- if config.username
36
- builder.request :basic_auth, config.username, config.password
37
- end
38
-
39
- if config.api_token
40
- builder.request :token_auth, config.api_token
41
- end
42
- end
43
-
44
- def configure_caching( builder )
45
- if config.cache[:metastore]
46
- dependency 'rack-cache'
47
-
48
- builder.use FaradayMiddleware::RackCompatible, Rack::Cache::Context, config.cache
49
- end
50
- end
51
-
52
- def dependency( lib = nil )
53
- lib ? require(lib) : yield
54
- rescue NameError, LoadError => err
55
- raise ConfigError, "Missing dependency for #{self}: #{err.message}"
56
- end
57
-
58
- end
59
- end
@@ -1,48 +0,0 @@
1
- require 'ostruct'
2
- require 'active_support/concern'
3
-
4
- class Frenetic
5
- module ResourceMockery
6
- extend ActiveSupport::Concern
7
-
8
- included do
9
- # I'm sure this violates some sort of CS principle or best practice,
10
- # but it solves the problem for now.
11
- superclass.send :instance_variable_set, '@mock_class', self
12
- end
13
-
14
- def attributes
15
- @params
16
- end
17
-
18
- def properties
19
- @params.each_with_object({}) do |(k,v), props|
20
- props[k] = v.class.to_s.underscore
21
- end
22
- end
23
-
24
- # Provides a place for a Resources that are mocked to declare reasonable
25
- # default values for Mock Resources
26
- def default_attributes
27
- {}
28
- end
29
-
30
- module ClassMethods
31
- def api_client
32
- superclass.api_client
33
- end
34
- end
35
-
36
- private
37
-
38
- def build_params( p )
39
- defaults = default_attributes.with_indifferent_access
40
- @params = defaults.merge( (p || {}).with_indifferent_access )
41
- end
42
-
43
- def build_structure
44
- @structure = OpenStruct.new( @attrs )
45
- end
46
-
47
- end
48
- end
@@ -1,88 +0,0 @@
1
- require 'addressable/uri'
2
- require 'active_support/core_ext/hash/indifferent_access'
3
-
4
- class Frenetic
5
- class Configuration
6
-
7
- @@defaults = {
8
- headers: {
9
- accept: 'application/hal+json',
10
- user_agent: "Frenetic v#{Frenetic::VERSION}; #{Socket.gethostname}"
11
- }
12
- }
13
-
14
- def initialize( cfg = {} )
15
- @_cfg = cfg.symbolize_keys
16
- end
17
-
18
- def adapter
19
- @_cfg[:adapter] || Faraday.default_adapter
20
- end
21
-
22
- def api_token
23
- @_cfg[:api_token]
24
- end
25
-
26
- def attributes
27
- {
28
- adapter: adapter,
29
- api_token: api_token,
30
- cache: cache,
31
- default_root_cache_age: default_root_cache_age,
32
- headers: headers,
33
- password: password,
34
- ssl: ssl,
35
- test_mode: test_mode,
36
- url: url,
37
- username: username
38
- }
39
- end
40
-
41
- def cache
42
- if @_cfg[:cache] == :rack
43
- {
44
- metastore: 'file:tmp/rack/meta',
45
- entitystore: 'file:tmp/rack/body',
46
- ignore_headers: %w{Authorization Set-Cookie X-Content-Digest}
47
- }
48
- else
49
- {}
50
- end
51
- end
52
-
53
- def default_root_cache_age
54
- @_cfg[:default_root_cache_age]
55
- end
56
-
57
- def headers
58
- @@defaults[:headers].merge( @_cfg[:headers] || {} ).tap do |h|
59
- if @_cfg[:headers] && @_cfg[:headers][:user_agent]
60
- if h[:user_agent] != @@defaults[:headers][:user_agent]
61
- h[:user_agent] = "#{h[:user_agent]} (#{@@defaults[:headers][:user_agent]})"
62
- end
63
- end
64
- end
65
- end
66
-
67
- def password
68
- @_cfg[:password] || @_cfg[:api_key]
69
- end
70
-
71
- def ssl
72
- @_cfg[:ssl] || { verify:true }
73
- end
74
-
75
- def test_mode
76
- @_cfg[:test_mode] || false
77
- end
78
-
79
- def url
80
- Addressable::URI.parse @_cfg[:url]
81
- end
82
-
83
- def username
84
- @_cfg[:username] || @_cfg[:app_id]
85
- end
86
-
87
- end
88
- end
@@ -1,50 +0,0 @@
1
- describe Frenetic::Configurable do
2
- let(:test_cfg) do
3
- {
4
- url:'http://example.org'
5
- }
6
- end
7
-
8
- subject(:instance) { Frenetic.new( test_cfg ) }
9
-
10
- describe '#config' do
11
- subject { instance.config }
12
-
13
- it { should_not be_empty }
14
- end
15
-
16
- describe '#configure' do
17
- subject do
18
- cfg = nil
19
- instance.configure { |c| cfg = c }
20
- cfg
21
- end
22
-
23
- it 'should yield the configuration' do
24
- subject.should be_a Hash
25
- end
26
- end
27
-
28
- describe '.configure' do
29
- subject { Frenetic.configure{|c|} }
30
-
31
- it 'should not exist' do
32
- expect{ subject }.to raise_error NoMethodError
33
- end
34
- end
35
-
36
- describe '#initialize' do
37
- let(:callback) do
38
- Proc.new { |b| }
39
- end
40
-
41
- subject do
42
- Frenetic.new( &callback ).instance_variable_get( "@builder_config" )
43
- end
44
-
45
- it 'retain block arguments' do
46
- subject.should eq callback
47
- end
48
- end
49
-
50
- end
@@ -1,56 +0,0 @@
1
- require 'spec_helper'
2
-
3
- require 'frenetic/resource_mockery'
4
-
5
- describe Frenetic::ResourceMockery do
6
- let(:my_temp_resource) do
7
- Class.new(Frenetic::Resource)
8
- end
9
-
10
- let(:my_mocked_resource) do
11
- Class.new(my_temp_resource) do
12
- def default_attributes
13
- { qux:'qux' }
14
- end
15
- end
16
- end
17
-
18
- before do
19
- stub_const 'MyNamespace::MyMockedResource', my_mocked_resource
20
-
21
- MyNamespace::MyMockedResource.send :include, described_class
22
- end
23
-
24
- let(:params) { { foo:1, bar:'baz' } }
25
-
26
- subject { MyNamespace::MyMockedResource.new params }
27
-
28
- it 'should violate some basic CS principles by telling the parent-class of its existence' do
29
- expect(my_temp_resource.instance_variables).to include :@mock_class
30
- end
31
-
32
- describe '#properties' do
33
- subject { super().properties }
34
-
35
- it 'should return a hash of available properties' do
36
- subject.should include 'foo' => 'fixnum'
37
- subject.should include 'bar' => 'string'
38
- end
39
- end
40
-
41
- describe '#attributes' do
42
- subject { super().attributes }
43
-
44
- it 'should return a hash of the resources attributes' do
45
- subject.should include 'foo' => 1
46
- subject.should include 'bar' => 'baz'
47
- subject.should include 'qux' => 'qux'
48
- end
49
- end
50
-
51
- describe '#default_attributes' do
52
- it 'should allow implementors to specify sane defaults' do
53
- subject.qux.should == 'qux'
54
- end
55
- end
56
- end
@@ -1,134 +0,0 @@
1
- describe Frenetic::Configuration do
2
- let(:cfg) { Hash.new }
3
-
4
- subject(:instance) { described_class.new cfg }
5
-
6
- describe '#adapter' do
7
- subject { instance.adapter }
8
-
9
- it { should == :net_http }
10
- end
11
-
12
- describe '#attributes' do
13
- subject { instance.attributes }
14
-
15
- it { should include :adapter }
16
- it { should include :api_token }
17
- it { should include :cache }
18
- it { should include :default_root_cache_age }
19
- it { should include :headers }
20
- it { should include :password }
21
- it { should include :ssl }
22
- it { should include :test_mode }
23
- it { should include :url }
24
- it { should include :username }
25
- end
26
-
27
- describe '#api_token' do
28
- let(:cfg) do
29
- { api_token:'API_TOKEN' }
30
- end
31
-
32
- subject { instance.api_token }
33
-
34
- it { should == 'API_TOKEN' }
35
- end
36
-
37
- describe '#cache' do
38
- subject { instance.cache }
39
-
40
- context 'with a value of :rack' do
41
- let(:cfg) do
42
- { cache: :rack }
43
- end
44
-
45
- it 'should return Rack::Cache options' do
46
- subject.should include metastore:'file:tmp/rack/meta'
47
- subject.should include entitystore:'file:tmp/rack/body'
48
- subject.should include ignore_headers:%w{Authorization Set-Cookie X-Content-Digest}
49
- end
50
- end
51
- end
52
-
53
- describe '#default_root_cache_age' do
54
- let(:cfg) do
55
- { default_root_cache_age:3600 }
56
- end
57
-
58
- subject { instance.default_root_cache_age }
59
-
60
- it { should == 3600 }
61
- end
62
-
63
- describe '#headers' do
64
- let(:cfg) do
65
- { headers:{ accept:'MIME', x_foo:'BAR' } }
66
- end
67
-
68
- subject { instance.headers }
69
-
70
- it 'should properly merge in nested header values' do
71
- subject.should include :user_agent
72
- subject.should include accept:'MIME'
73
- subject.should include x_foo:'BAR'
74
- end
75
-
76
- context 'with a custom User-Agent' do
77
- let(:cfg) do
78
- { headers:{ user_agent:'Foo v1.1' } }
79
- end
80
-
81
- it 'should append the Frenentic User-Agent' do
82
- subject[:user_agent].should match %r{\AFoo v1.1 \(Frenetic v.[^;]*; [^)]*\)\Z}
83
- end
84
- end
85
- end
86
-
87
- describe '#password' do
88
- subject { instance.password }
89
-
90
- context 'with a specifed Api key' do
91
- let(:cfg) do
92
- { api_key:'API_KEY' }
93
- end
94
-
95
- it { should == 'API_KEY' }
96
- end
97
- end
98
-
99
- describe '#ssl' do
100
- subject { instance.ssl }
101
-
102
- it { should include verify:true }
103
- end
104
-
105
- describe '#test_mode' do
106
- subject { instance.test_mode }
107
-
108
- it { should be_false }
109
- end
110
-
111
- describe '#url' do
112
- let(:cfg) do
113
- { url:'http://example.org' }
114
- end
115
-
116
- subject { instance.url }
117
-
118
- it { should be_a Addressable::URI }
119
-
120
- its(:to_s) { should == 'http://example.org' }
121
- end
122
-
123
- describe '#username' do
124
- subject { instance.username }
125
-
126
- context 'with a specifed App Id' do
127
- let(:cfg) do
128
- { app_id:'APP_ID' }
129
- end
130
-
131
- it { should == 'APP_ID' }
132
- end
133
- end
134
- end