reviewed 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/lib/reviewed/article.rb +10 -8
  2. data/lib/reviewed/attachment.rb +4 -0
  3. data/lib/reviewed/base.rb +25 -40
  4. data/lib/reviewed/client.rb +56 -0
  5. data/lib/reviewed/collection.rb +16 -19
  6. data/lib/reviewed/configurable.rb +26 -0
  7. data/lib/reviewed/embeddable.rb +74 -0
  8. data/lib/reviewed/page.rb +4 -0
  9. data/lib/reviewed/product.rb +6 -2
  10. data/lib/reviewed/utils.rb +25 -0
  11. data/lib/reviewed/version.rb +1 -1
  12. data/lib/reviewed.rb +20 -33
  13. data/reviewed.gemspec +2 -1
  14. data/spec/article_spec.rb +65 -39
  15. data/spec/base_spec.rb +39 -74
  16. data/spec/client_spec.rb +95 -0
  17. data/spec/collection_spec.rb +5 -6
  18. data/spec/configurable_spec.rb +44 -0
  19. data/spec/embeddable_spec.rb +176 -0
  20. data/spec/fixtures/vcr/article/attachments.yml +464 -457
  21. data/spec/fixtures/vcr/article/find_page.yml +115 -111
  22. data/spec/fixtures/vcr/article/products.yml +464 -457
  23. data/spec/fixtures/vcr/base/article/find.yml +7618 -0
  24. data/spec/fixtures/vcr/base/where_collection.yml +600 -7626
  25. data/spec/fixtures/vcr/collection/products.yml +501 -498
  26. data/spec/fixtures/vcr/product/attachments.yml +94 -68
  27. data/spec/fixtures/vcr/utils/collection.yml +346 -0
  28. data/spec/fixtures/vcr/utils/object.yml +7618 -0
  29. data/spec/fixtures/vcr/utils.yml +7961 -0
  30. data/spec/product_spec.rb +31 -17
  31. data/spec/reviewed_spec.rb +19 -0
  32. data/spec/utils_spec.rb +40 -0
  33. metadata +45 -22
  34. data/lib/reviewed/request.rb +0 -23
  35. data/lib/reviewed/response.rb +0 -12
  36. data/lib/reviewed/util.rb +0 -16
  37. data/spec/fixtures/vcr/base/find_error_key.yml +0 -172
  38. data/spec/fixtures/vcr/base/find_ok.yml +0 -1155
  39. data/spec/fixtures/vcr/request/authors.yml +0 -133
  40. data/spec/fixtures/vcr/response/authors.yml +0 -133
  41. data/spec/request_spec.rb +0 -15
  42. data/spec/response_spec.rb +0 -26
  43. data/spec/util_spec.rb +0 -33
@@ -1,27 +1,29 @@
1
+ require 'reviewed/page'
2
+ require 'reviewed/product'
3
+ require 'reviewed/attachment'
4
+
1
5
  module Reviewed
2
6
  class Article < Base
7
+ has_many :pages
8
+ has_many :products
9
+ has_many :attachments
10
+
3
11
  def find_page(slug)
4
12
  pages.find { |page| page.slug.match(/#{slug}/i) }
5
13
  end
6
14
 
7
- def products
8
- (@attributes[:products] || []).map do |product|
9
- Reviewed::Product.new(product)
10
- end
11
- end
12
-
13
15
  def primary_product
14
16
  products.select { |p| p.id == primary_product_id }.first
15
17
  end
16
18
 
17
19
  def attachments(tag=nil)
18
20
  if tag.present?
19
- @attributes[:attachments].select do |attachment|
21
+ @attributes.attachments.select do |attachment|
20
22
  attachment_tags = attachment.tags || []
21
23
  attachment_tags.map(&:downcase).include?(tag.downcase)
22
24
  end
23
25
  else
24
- @attributes[:attachments]
26
+ @attributes.attachments
25
27
  end
26
28
  end
27
29
  end
@@ -0,0 +1,4 @@
1
+ module Reviewed
2
+ class Attachment < Reviewed::Base
3
+ end
4
+ end
data/lib/reviewed/base.rb CHANGED
@@ -1,18 +1,35 @@
1
+ require 'active_model'
2
+
1
3
  module Reviewed
2
4
  class Base
3
- extend ActiveModel::Naming
5
+ include ::Reviewed::Embeddable
6
+ include ::Reviewed::Utils
7
+
8
+ extend ::ActiveModel::Naming
9
+
10
+ attr_accessor :attributes
11
+
12
+ def initialize(data)
13
+ self.attributes = objectify(data)
14
+ end
15
+
16
+ class << self
4
17
 
5
- attr_accessor :raw_response, :resource_url
18
+ def find(id, params={})
19
+ object_from_response(:get, "#{resource_url}/#{id}", params)
20
+ end
6
21
 
7
- def initialize(attributes={}, raw_response=nil)
8
- attributes.symbolize_keys!
22
+ def where(params={})
23
+ collection_from_response(:get, resource_url, params)
24
+ end
9
25
 
10
- unless attributes[:id].present?
11
- raise ResourceError.new("Resource requires an ID")
26
+ def all
27
+ where({})
12
28
  end
13
29
 
14
- @raw_response = raw_response
15
- @attributes = Hashie::Mash.new(attributes)
30
+ def resource_url
31
+ @resource_name ||= self.name.demodulize.downcase.pluralize
32
+ end
16
33
  end
17
34
 
18
35
  def method_missing(sym, *args, &block)
@@ -22,37 +39,5 @@ module Reviewed
22
39
  super
23
40
  end
24
41
  end
25
-
26
- def self.find(id)
27
- Reviewed.verify_key!
28
-
29
- response = Reviewed::Request.get(resource_url(id))
30
- new(response.json, response.raw)
31
- end
32
-
33
- def self.all
34
- where({})
35
- end
36
-
37
- def self.where(options={})
38
- Reviewed.verify_key!
39
-
40
- response = Reviewed::Request.get(resource_url(nil, options))
41
- Collection.new(self, response.json, options)
42
- end
43
-
44
- def self.resource_name=(value)
45
- @resource_name = value
46
- end
47
-
48
- def self.resource_name
49
- @resource_name ||= self.name.split('::').last.downcase
50
- end
51
-
52
- def self.resource_url(id=nil, options={})
53
- url = [Reviewed.base_uri, API_VERSION, resource_name.pluralize, id].compact.join("/")
54
- query_string = Util.build_query_string(options)
55
- query_string.blank? ? url : "#{url}?#{query_string}"
56
- end
57
42
  end
58
43
  end
@@ -0,0 +1,56 @@
1
+ module Reviewed
2
+ class Client
3
+ include ::Reviewed::Configurable
4
+
5
+ attr_accessor :api_key, :base_uri, :api_version
6
+
7
+ def initialize
8
+ Reviewed::Configurable.options.each do |key, value|
9
+ instance_variable_set(:"@#{key}", value)
10
+ end
11
+ end
12
+
13
+ # Perform an HTTP DELETE request
14
+ def delete(path, params={})
15
+ request(:delete, path, params)
16
+ end
17
+
18
+ # Perform an HTTP GET request
19
+ def get(path, params={})
20
+ request(:get, path, params)
21
+ end
22
+
23
+ # Perform an HTTP POST request
24
+ def post(path, params={})
25
+ request(:post, path, params)
26
+ end
27
+
28
+ # Perform an HTTP PUT request
29
+ def put(path, params={})
30
+ request(:put, path, params)
31
+ end
32
+
33
+ def url
34
+ [base_uri, api_version].join('/')
35
+ end
36
+
37
+ private
38
+
39
+ def request(method, path, params={})
40
+ verify_key!
41
+
42
+ connection.send(method.to_sym, path, params) do |request|
43
+ request.headers['X-Reviewed-Authorization'] ||= Reviewed.api_key
44
+ end
45
+ end
46
+
47
+ def connection
48
+ @connection ||= ::Faraday.new(url: url) do |faraday|
49
+ faraday.response :mashify
50
+ faraday.response :json
51
+ faraday.request :url_encoded
52
+ faraday.adapter Faraday.default_adapter
53
+ end
54
+ end
55
+ end
56
+ end
@@ -1,25 +1,26 @@
1
1
  module Reviewed
2
2
  class Collection
3
+ include Reviewed::Utils
3
4
  include Enumerable
5
+
4
6
  extend Forwardable
7
+
5
8
  def_delegators :@items, :<<, :[], :[]=, :each, :first, :last, :length, :concat, :map, :collect, :empty?
6
9
 
7
- attr_accessor :raw_response
10
+ attr_accessor :raw_response, :page_attributes, :klass, :items, :params
8
11
 
9
- def initialize(klass, json, options={})
10
- json = json.symbolize_keys!
11
- page_data = json[:pagination].symbolize_keys!
12
+ def initialize(klass, response, params={})
13
+ body = response.body
14
+ data = body.data
12
15
 
13
- @items = []
14
- items = json[:data]
15
- items.each do |item|
16
- @items << klass.new(item)
17
- end
16
+ self.page_attributes = body.pagination
17
+ self.params = params
18
+ self.klass = klass
19
+ self.items = []
18
20
 
19
- @page_attributes = page_data
20
- @raw_response = json
21
- @request_options = options.symbolize_keys!
22
- @klass = klass
21
+ data.each do |obj|
22
+ self.items << klass.from_response(obj)
23
+ end
23
24
  end
24
25
 
25
26
  def limit_value
@@ -44,10 +45,6 @@ module Reviewed
44
45
  fetch_page(@page_attributes[:previous_page])
45
46
  end
46
47
 
47
- def ==(other)
48
- @raw_response == other.raw_response
49
- end
50
-
51
48
  def method_missing(sym, *args, &block)
52
49
  clean_sym = sym.to_s.gsub(/\?/, '').to_sym
53
50
  if @page_attributes.has_key?(clean_sym)
@@ -60,8 +57,8 @@ module Reviewed
60
57
  private
61
58
 
62
59
  def fetch_page(page=nil)
63
- @request_options[:page] = page
64
- @klass.where(@request_options)
60
+ self.params[:page] = page
61
+ @klass.where(self.params)
65
62
  end
66
63
  end
67
64
  end
@@ -0,0 +1,26 @@
1
+ module Reviewed
2
+ module Configurable
3
+
4
+ class << self
5
+
6
+ def options
7
+ {
8
+ api_key: nil,
9
+ base_uri: 'http://localhost:3000/api',
10
+ api_version: 'v1'
11
+ }
12
+ end
13
+ end
14
+
15
+ def configure
16
+ yield self
17
+ self
18
+ end
19
+
20
+ def verify_key!
21
+ unless Reviewed.api_key
22
+ raise ConfigurationError.new("Please set Reviewed.api_key before making a request")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,74 @@
1
+ module Reviewed
2
+ module Embeddable
3
+
4
+ def self.included(klass)
5
+ klass.extend(Reviewed::Embeddable::ClassMethods)
6
+ end
7
+
8
+ class << self
9
+
10
+ def embedded_class(name, opts_name=nil)
11
+ name = opts_name ? opts_name : embedded_name(name)
12
+ name.constantize
13
+ end
14
+
15
+ def embedded_name(name)
16
+ ["Reviewed", name.singularize.classify].join("::")
17
+ end
18
+ end
19
+
20
+ def objectify(data)
21
+ data = objectify_has_many(data)
22
+ data = objectify_has_one(data)
23
+ return data
24
+ end
25
+
26
+ def objectify_has_many(json)
27
+ self.class._embedded_many.each do |map|
28
+ key, value = [map.keys[0], map.values[0]]
29
+
30
+ if json.has_key?(key)
31
+ json[key] = json[key].map do |obj|
32
+ value.new(obj)
33
+ end
34
+ end
35
+ end
36
+ return json
37
+ end
38
+
39
+ def objectify_has_one(json)
40
+ self.class._embedded_one.each do |map|
41
+ key, value = [map.keys[0], map.values[0]]
42
+
43
+ if json.has_key?(key)
44
+ json[key] = value.new(json[key])
45
+ end
46
+ end
47
+ return json
48
+ end
49
+
50
+ module ClassMethods
51
+ attr_accessor :_embedded_many, :_embedded_one
52
+
53
+ def has_many(name, opts={})
54
+ klass = Reviewed::Embeddable.embedded_class(name.to_s, opts[:class_name])
55
+ association = opts[:as] || name
56
+ _embedded_many << { association.to_s => klass }
57
+ end
58
+
59
+ def has_one(name, opts={})
60
+ klass = Reviewed::Embeddable.embedded_class(name.to_s, opts[:class_name])
61
+ association = opts[:as] || name
62
+ _embedded_one << { association.to_s => klass }
63
+ end
64
+
65
+ def _embedded_many
66
+ @_embedded_many ||= []
67
+ end
68
+
69
+ def _embedded_one
70
+ @_embedded_one ||= []
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,4 @@
1
+ module Reviewed
2
+ class Page < Base
3
+ end
4
+ end
@@ -1,13 +1,17 @@
1
+ require 'reviewed/attachment'
2
+
1
3
  module Reviewed
2
4
  class Product < Base
5
+ has_many :attachments
6
+
3
7
  def attachments(tag=nil)
4
8
  if tag.present?
5
- @attributes[:attachments].select do |attachment|
9
+ @attributes.attachments.select do |attachment|
6
10
  attachment_tags = attachment.tags || []
7
11
  attachment_tags.map(&:downcase).include?(tag.downcase)
8
12
  end
9
13
  else
10
- @attributes[:attachments]
14
+ @attributes.attachments
11
15
  end
12
16
  end
13
17
  end
@@ -0,0 +1,25 @@
1
+ module Reviewed
2
+ module Utils
3
+
4
+ def self.included(klass)
5
+ klass.extend(Reviewed::Utils::ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+
10
+ def object_from_response(method, url, params={})
11
+ response = Reviewed.send(method, url, params)
12
+ self.from_response(response.body)
13
+ end
14
+
15
+ def collection_from_response(method, url, params={})
16
+ response = Reviewed.send(method, url, params)
17
+ Reviewed::Collection.new(self, response, params)
18
+ end
19
+
20
+ def from_response(data)
21
+ self.new(data)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,4 +1,4 @@
1
1
  module Reviewed
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  API_VERSION = 'v1'
4
4
  end
data/lib/reviewed.rb CHANGED
@@ -1,53 +1,40 @@
1
1
  $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__)))
2
2
 
3
+ require 'faraday'
4
+ require 'faraday_middleware'
5
+ require 'active_support/inflector'
3
6
  require 'active_support/core_ext'
4
- require 'rest_client'
5
7
  require 'active_model'
6
8
  require 'hashie'
7
- require 'forwardable'
8
9
 
9
- require 'reviewed/version'
10
- require 'reviewed/util'
11
- require 'reviewed/base'
10
+ require 'reviewed/configurable'
11
+ require 'reviewed/embeddable'
12
+ require 'reviewed/utils'
13
+ require 'reviewed/client'
12
14
  require 'reviewed/collection'
13
- require 'reviewed/request'
14
- require 'reviewed/response'
15
+ require 'reviewed/base'
15
16
 
16
- require 'reviewed/website'
17
17
  require 'reviewed/product'
18
+ require 'reviewed/article'
18
19
  require 'reviewed/author'
19
20
  require 'reviewed/brand'
20
- require 'reviewed/article'
21
+ require 'reviewed/page'
22
+ require 'reviewed/website'
23
+
21
24
 
22
25
  module Reviewed
23
26
  class ConfigurationError < StandardError; end
24
- class ResourceError < StandardError; end
25
-
26
- @@config = {
27
- base_uri: 'http://localhost:3000/api'
28
- }
29
27
 
30
- def self.api_key=(token)
31
- @@config[:api_key] = token
32
- end
33
-
34
- def self.api_key
35
- @@config[:api_key]
36
- end
37
-
38
- def self.base_uri=(uri)
39
- @@config[:base_uri] = uri
40
- end
28
+ class << self
41
29
 
42
- def self.base_uri
43
- @@config[:base_uri]
44
- end
30
+ def client
31
+ @client ||= Reviewed::Client.new
32
+ end
45
33
 
46
- def self.verify_key!
47
- if Reviewed.api_key.present?
48
- true
49
- else
50
- raise ConfigurationError.new("Please set Reviewed.api_key before making a request")
34
+ def method_missing(method, *args, &block)
35
+ return super unless client.respond_to?(method)
36
+ client.send(method, *args, &block)
51
37
  end
52
38
  end
53
39
  end
40
+
data/reviewed.gemspec CHANGED
@@ -17,7 +17,8 @@ Gem::Specification.new do |gem|
17
17
 
18
18
  gem.add_dependency 'activesupport', '>= 3.0'
19
19
  gem.add_dependency 'activemodel', '>=3.0'
20
- gem.add_dependency 'rest-client', '>= 1.6'
20
+ gem.add_dependency 'faraday', '>= 0.8.4'
21
+ gem.add_dependency 'faraday_middleware', '>= 0.9.0'
21
22
  gem.add_dependency 'hashie', '~> 1.2'
22
23
 
23
24
  gem.add_development_dependency 'rspec', '>= 2.10'
data/spec/article_spec.rb CHANGED
@@ -1,6 +1,71 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Reviewed::Article do
4
+
5
+ describe 'associations' do
6
+
7
+ describe 'pages' do
8
+ use_vcr_cassette 'article/pages'
9
+
10
+ it 'has_many :pages' do
11
+ Reviewed::Article._embedded_many.should include({"pages"=>Reviewed::Page})
12
+ end
13
+ end
14
+
15
+ describe 'products' do
16
+ use_vcr_cassette 'article/products'
17
+
18
+ before(:each) do
19
+ @article = Reviewed::Article.find('big-green-egg-medium-charcoal-grill-review')
20
+ end
21
+
22
+ it 'has_many :products' do
23
+ Reviewed::Article._embedded_many.should include({"products"=>Reviewed::Product})
24
+ end
25
+
26
+ it 'returns products of the correct class' do
27
+ @article.products.each do |product|
28
+ product.should be_an_instance_of(Reviewed::Product)
29
+ end
30
+ end
31
+ end
32
+
33
+ describe 'attachments' do
34
+ use_vcr_cassette 'article/attachments'
35
+
36
+ before(:each) do
37
+ @article = Reviewed::Article.find('big-green-egg-medium-charcoal-grill-review')
38
+ end
39
+
40
+ it 'has_many :attachments' do
41
+ Reviewed::Article._embedded_many.should include({"attachments"=>Reviewed::Attachment})
42
+ end
43
+
44
+ it 'returns all attachments' do
45
+ @article.attachments.length.should >= 1
46
+ end
47
+
48
+ it 'returns attachments of the correct class' do
49
+ @article.attachments.each do |attachment|
50
+ attachment.should be_an_instance_of(Reviewed::Attachment)
51
+ end
52
+ end
53
+
54
+ it 'finds attachments by tag' do
55
+ attachments = @article.attachments('hero')
56
+ attachments.length.should == 1
57
+ attachments.each do |attachment|
58
+ attachment.tags.join(',').should match(/hero/i)
59
+ end
60
+ end
61
+
62
+ it 'does not have any matching attachments' do
63
+ attachments = @article.attachments('doesnotcompute')
64
+ attachments.length.should == 0
65
+ end
66
+ end
67
+ end
68
+
4
69
  describe 'find_page' do
5
70
  use_vcr_cassette 'article/find_page'
6
71
 
@@ -13,20 +78,6 @@ describe Reviewed::Article do
13
78
  end
14
79
  end
15
80
 
16
- describe 'products' do
17
- use_vcr_cassette 'article/products'
18
-
19
- before(:each) do
20
- @article = Reviewed::Article.find('big-green-egg-medium-charcoal-grill-review')
21
- end
22
-
23
- it 'returns products of the correct class' do
24
- @article.products.should_not be_empty
25
- @article.products.each do |product|
26
- product.class.should == Reviewed::Product
27
- end
28
- end
29
- end
30
81
 
31
82
  describe 'primary_product' do
32
83
  use_vcr_cassette 'article/products'
@@ -44,29 +95,4 @@ describe Reviewed::Article do
44
95
  @product.class.should == Reviewed::Product
45
96
  end
46
97
  end
47
-
48
- describe 'attachments' do
49
- use_vcr_cassette 'article/attachments'
50
-
51
- before(:each) do
52
- @article = Reviewed::Article.find('big-green-egg-medium-charcoal-grill-review')
53
- end
54
-
55
- it 'returns all attachments' do
56
- @article.attachments.length.should >= 1
57
- end
58
-
59
- it 'finds attachments by tag' do
60
- attachments = @article.attachments('hero')
61
- attachments.length.should == 1
62
- attachments.each do |attachment|
63
- attachment.tags.join(',').should match(/hero/i)
64
- end
65
- end
66
-
67
- it 'does not have any matching attachments' do
68
- attachments = @article.attachments('doesnotcompute')
69
- attachments.length.should == 0
70
- end
71
- end
72
98
  end