reviewed 0.0.6 → 0.0.7

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 (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