rest_model 0.2.1 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.travis.yml +5 -0
  2. data/README.md +1 -1
  3. data/Rakefile +1 -1
  4. data/examples/embeds_many/simple.rb +2 -0
  5. data/lib/rest_model/configuration.rb +4 -4
  6. data/lib/rest_model/errors.rb +1 -1
  7. data/lib/rest_model/key/embeddable.rb +1 -1
  8. data/lib/rest_model/key/href/response.rb +1 -1
  9. data/lib/rest_model/key/property/retriever.rb +1 -1
  10. data/lib/rest_model/key/property/sender.rb +1 -1
  11. data/lib/rest_model/key/relation/response.rb +1 -1
  12. data/lib/rest_model/key/relation.rb +4 -0
  13. data/lib/rest_model/key.rb +4 -0
  14. data/lib/rest_model/response.rb +3 -4
  15. data/lib/rest_model/serialization/boolean.rb +2 -2
  16. data/lib/rest_model/serialization/date.rb +3 -3
  17. data/lib/rest_model/serialization/date_time.rb +3 -3
  18. data/lib/rest_model/serialization/enumerable.rb +2 -2
  19. data/lib/rest_model/serialization/float.rb +2 -2
  20. data/lib/rest_model/serialization/integer.rb +6 -4
  21. data/lib/rest_model/serialization/string.rb +2 -2
  22. data/lib/rest_model/serialization/symbol.rb +2 -2
  23. data/lib/rest_model/version.rb +1 -1
  24. data/lib/rest_model.rb +2 -1
  25. data/rest_model.gemspec +4 -6
  26. data/spec/spec_helper.rb +0 -1
  27. data/spec/support/examples.rb +14 -20
  28. data/spec/unit/configuration_spec.rb +4 -6
  29. data/spec/unit/key/association_spec.rb +18 -42
  30. data/spec/unit/key/embeddable/response_spec.rb +1 -1
  31. data/spec/unit/key/embeddable_spec.rb +23 -0
  32. data/spec/unit/key/property/response_spec.rb +6 -6
  33. data/spec/unit/key/property/retriever_spec.rb +2 -2
  34. data/spec/unit/key/relation/response_spec.rb +97 -1
  35. data/spec/unit/key/relation_spec.rb +13 -52
  36. data/spec/unit/key_spec.rb +13 -9
  37. data/spec/unit/response_spec.rb +43 -5
  38. data/spec/unit/serialization/date_spec.rb +4 -0
  39. data/spec/unit/serialization/date_time_spec.rb +4 -0
  40. data/spec/unit/serialization/integer_spec.rb +8 -0
  41. data/spec/unit/source/path_spec.rb +3 -3
  42. data/spec/unit/source/retriever_spec.rb +9 -9
  43. metadata +31 -71
  44. data/Guardfile +0 -7
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ script: rspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # RestModel
1
+ # RestModel [![Build Status](https://secure.travis-ci.org/rodrigues/rest_model.png)](http://travis-ci.org/rodrigues/rest_model)
2
2
 
3
3
  [ THE INTERNETS ]
4
4
 
data/Rakefile CHANGED
@@ -1,2 +1,2 @@
1
- require 'bundler'
1
+ require "bundler"
2
2
  Bundler::GemHelper.install_tasks
@@ -1,3 +1,5 @@
1
+ # encoding: utf-8
2
+
1
3
  $:.push 'examples'; require 'helper'
2
4
 
3
5
  class Item < RestModel
@@ -6,6 +6,10 @@ class RestModel
6
6
 
7
7
  DefaultHandler = proc {|keys| keys}
8
8
 
9
+ def configure
10
+ yield self if block_given?
11
+ end
12
+
9
13
  def convert_input_keys
10
14
  @convert_input_keys || DefaultHandler
11
15
  end
@@ -45,9 +49,5 @@ class RestModel
45
49
  def date_time_format=(format)
46
50
  @date_time_format = format
47
51
  end
48
-
49
- def configure
50
- yield self if block_given?
51
- end
52
52
  end
53
53
  end
@@ -17,4 +17,4 @@ class RestModel
17
17
  new(errors)
18
18
  end
19
19
  end
20
- end
20
+ end
@@ -19,7 +19,7 @@ class RestModel
19
19
  end
20
20
 
21
21
  def raw?
22
- [Hash, Array].include?(resource_class)
22
+ %w(Hash Array).include?(@class_name.to_s.camelize)
23
23
  end
24
24
 
25
25
  def from_hash(attrs, resource = nil)
@@ -3,7 +3,7 @@ class RestModel
3
3
  module Response
4
4
  def to_resource(parent)
5
5
  id_key = parent.class.id_key.name
6
- {name => "#{RestModel::Configuration.host}/#{parent.class.resource_name}/#{parent.send(id_key)}"}
6
+ {name => URI.escape("#{RestModel::Configuration.host}/#{parent.class.resource_name}/#{parent.send(id_key)}")}
7
7
  end
8
8
  end
9
9
  end
@@ -4,7 +4,7 @@ class RestModel
4
4
  def from_source(item, resource = nil)
5
5
  value = digg(item)
6
6
  translation.translates_from_source? ? translation.translate_from_source(value, resource)
7
- : serializer.serialize(value)
7
+ : serializer.serialize(value, self.options)
8
8
  end
9
9
 
10
10
  def digg(input)
@@ -4,7 +4,7 @@ class RestModel
4
4
  def to_source!(value, resource, options = {})
5
5
  source_value = begin
6
6
  translation.translates_to_source? ? translation.translate_to_source(value, resource)
7
- : serializer.desserialize(value)
7
+ : serializer.desserialize(value, self.options)
8
8
 
9
9
  rescue TranslationError, SerializationError => error
10
10
  raise error if options[:fail] and validates?(value)
@@ -12,7 +12,7 @@ class RestModel
12
12
  return nil unless visible?(parent)
13
13
 
14
14
  href = href(parent)
15
- href ? {rel: name, href: href} : nil
15
+ href ? {rel: name, href: URI.escape(href)} : nil
16
16
  end
17
17
 
18
18
  private
@@ -20,6 +20,10 @@ class RestModel
20
20
  nil
21
21
  end
22
22
 
23
+ def relation?
24
+ true
25
+ end
26
+
23
27
  alias :parse :from_source
24
28
  end
25
29
  end
@@ -40,5 +40,9 @@ class RestModel
40
40
  else visible
41
41
  end
42
42
  end
43
+
44
+ def relation?
45
+ false
46
+ end
43
47
  end
44
48
  end
@@ -10,15 +10,14 @@ class RestModel
10
10
  buffer.merge!(key.to_resource(self))
11
11
  end
12
12
 
13
- if root and self.class.relations.any? and !options[:summarize]
14
- links = build_links
15
- resource.merge!({link: links}) if links.any?
13
+ if (links = build_links).any? && !options[:summarize]
14
+ resource.merge!(link: links)
16
15
  end
17
16
  end
18
17
  end
19
18
 
20
19
  def build_links
21
- self.class.relations.map {|key| key.to_relation(self)}.reject(&:nil?)
20
+ self.class.relations.map {|key| key.to_relation(self)}.compact
22
21
  end
23
22
 
24
23
  def resource_keys(options)
@@ -25,13 +25,13 @@ class RestModel
25
25
  nil => false
26
26
  }.freeze
27
27
 
28
- def self.serialize(value)
28
+ def self.serialize(value, options = {})
29
29
  MAPPINGS[value].tap do |bool|
30
30
  fail SerializationError, "value '#{value}' is not boolean" if bool.nil?
31
31
  end
32
32
  end
33
33
 
34
- def self.desserialize(value)
34
+ def self.desserialize(value, options = {})
35
35
  fail SerializationError, "value '#{value}' is not boolean" unless boolean?(value)
36
36
 
37
37
  value ? RestModel::Configuration.true_value
@@ -1,15 +1,15 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class Date
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  ::Date.parse value
6
6
  rescue
7
7
  raise SerializationError, "value '#{value}' is an invalid date"
8
8
  end
9
9
 
10
- def self.desserialize(value)
10
+ def self.desserialize(value, options = {})
11
11
  date = value.kind_of?(::Date) ? value : ::Date.parse(value)
12
- format = RestModel::Configuration.date_format
12
+ format = options.fetch(:format, RestModel::Configuration.date_format)
13
13
  format ? date.strftime(format) : date.to_s
14
14
  rescue
15
15
  raise SerializationError, "value '#{value}' is an invalid date"
@@ -1,15 +1,15 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class DateTime
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  ::DateTime.parse value
6
6
  rescue
7
7
  raise SerializationError, "value '#{value}' is an invalid date time"
8
8
  end
9
9
 
10
- def self.desserialize(value)
10
+ def self.desserialize(value, options = {})
11
11
  date_time = value.kind_of?(::DateTime) ? value : ::DateTime.parse(value)
12
- format = RestModel::Configuration.date_time_format
12
+ format = options.fetch(:format, RestModel::Configuration.date_time_format)
13
13
  format ? date_time.strftime(format) : date_time.to_s
14
14
  rescue
15
15
  raise SerializationError, "value '#{value}' is an invalid date time"
@@ -1,13 +1,13 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class Enumerable
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  fail SerializationError, "value '#{value}' is not an enumerable" unless value.kind_of?(::Enumerable)
6
6
 
7
7
  value
8
8
  end
9
9
 
10
- def self.desserialize(value)
10
+ def self.desserialize(value, options = {})
11
11
  fail SerializationError, "value '#{value}' is not an enumerable" unless value.kind_of?(::Enumerable)
12
12
 
13
13
  value
@@ -1,13 +1,13 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class Float
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  Float(value)
6
6
  rescue
7
7
  raise SerializationError, "value '#{value}' is not a float"
8
8
  end
9
9
 
10
- def self.desserialize(value)
10
+ def self.desserialize(value, options = {})
11
11
  Float(value)
12
12
  rescue
13
13
  raise SerializationError, "value '#{value}' is not a float"
@@ -1,10 +1,10 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class Integer
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  case value
6
6
  when ::String
7
- if value =~ /^\d+$/
7
+ if value =~ /^\-?\d+$/
8
8
  value.to_i
9
9
  else
10
10
  raise
@@ -16,8 +16,10 @@ class RestModel
16
16
  raise SerializationError, "value '#{value}' is not an integer"
17
17
  end
18
18
 
19
- def self.desserialize(value)
20
- serialize(value)
19
+ def self.desserialize(value, options = {})
20
+ length = options.fetch(:padding_zeros, 0)
21
+ return serialize(value) if length == 0
22
+ serialize(value).to_s.rjust(length, "0")
21
23
  end
22
24
  end
23
25
  end
@@ -1,13 +1,13 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class String
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  value.nil? ? nil : value.to_s
6
6
  rescue
7
7
  raise SerializationError, "value '#{value}' is not a string"
8
8
  end
9
9
 
10
- def self.desserialize(value)
10
+ def self.desserialize(value, options = {})
11
11
  serialize(value)
12
12
  end
13
13
  end
@@ -1,13 +1,13 @@
1
1
  class RestModel
2
2
  module Serialization
3
3
  class Symbol
4
- def self.serialize(value)
4
+ def self.serialize(value, options = {})
5
5
  value.to_s.to_sym
6
6
  rescue
7
7
  raise SerializationError, "value '#{value}' is not a symbol"
8
8
  end
9
9
 
10
- def self.desserialize(value)
10
+ def self.desserialize(value, options = {})
11
11
  serialize(value)
12
12
  end
13
13
  end
@@ -1,3 +1,3 @@
1
1
  class RestModel
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.3"
3
3
  end
data/lib/rest_model.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "date"
2
+ require "uri"
2
3
  require "active_support/inflector"
3
4
  require "active_support/concern"
4
5
  require "active_support/core_ext/object"
@@ -96,7 +97,7 @@ class RestModel
96
97
  end
97
98
 
98
99
  def self.relations
99
- @keys.find_all {|k| k.kind_of?(Relation)}
100
+ keys.find_all(&:relation?)
100
101
  end
101
102
 
102
103
  def self.resource_name(custom_name = nil)
data/rest_model.gemspec CHANGED
@@ -17,10 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
18
  s.require_paths = ["lib"]
19
19
 
20
- s.add_dependency "activesupport", "~> 3.0"
21
- s.add_dependency "i18n", ">= 0.5"
22
- s.add_development_dependency "rspec", "~> 2.6"
23
- s.add_development_dependency "guard", "~> 0.5"
24
- s.add_development_dependency "guard-rspec", "~> 0.4"
25
- s.add_development_dependency "growl", "~> 1.0"
20
+ s.add_dependency "activesupport", "~> 3.2"
21
+ s.add_dependency "i18n", ">= 0.6"
22
+ s.add_development_dependency "rspec", "~> 2.6"
23
+ s.add_development_dependency "rake"
26
24
  end
data/spec/spec_helper.rb CHANGED
@@ -19,7 +19,6 @@ RSpec.configure do |config|
19
19
  end
20
20
 
21
21
  include Output
22
- include Examples
23
22
 
24
23
  RestModel::Configuration.configure do |c|
25
24
  c.host = 'http://example.com'
@@ -1,27 +1,21 @@
1
- module Examples
2
- extend RSpec::Core::Hooks
1
+ EXAMPLES_CONSTANTS = %w(Root Item Customer Entry
2
+ Service Billing Developer Upcasing
3
+ Camelizing Product Address Phone)
3
4
 
4
- CONSTANTS = [:Root, :Item, :Customer, :Entry, :Phone,
5
- :Service, :Billing, :Developer, :Upcasing,
6
- :Camelizing, :Product, :Address]
7
-
8
- def describe_example(file, tags = {}, &block)
9
- describe "example #{file}", tags do
10
- before :all do
11
- CONSTANTS.each do |klass|
12
- self.class.ancestors.concat([self.class, Examples]).each do |mod|
13
- mod.send(:remove_const, klass) if mod.const_defined?(klass, false)
14
- end
15
- end
16
-
17
- RestModel::Configuration.configure do |c|
18
- c.convert_input_keys = RestModel::Configuration::DefaultHandler
19
- end
5
+ def describe_example(file, tags = {}, &block)
6
+ describe "example #{file}", tags do
7
+ before :all do
8
+ EXAMPLES_CONSTANTS.each do |klass|
9
+ Object.send(:remove_const, klass) if Object.const_defined?(klass, false)
10
+ end
20
11
 
21
- silently {eval File.read("examples/#{file}.rb")}
12
+ RestModel::Configuration.configure do |c|
13
+ c.convert_input_keys = RestModel::Configuration::DefaultHandler
22
14
  end
23
15
 
24
- instance_eval &block if block
16
+ silently {eval File.read("examples/#{file}.rb")}
25
17
  end
18
+
19
+ instance_eval &block if block
26
20
  end
27
21
  end
@@ -1,24 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RestModel::Configuration do
4
- after(:all) do
5
- RestModel::Configuration.convert_input_keys = nil
6
- end
4
+ after(:all) {subject.convert_input_keys = nil}
7
5
 
8
6
  context "when no custom input keys converter is set" do
9
7
  it "returns default key converter" do
10
8
  default_handler = RestModel::Configuration::DefaultHandler
11
- RestModel::Configuration.convert_input_keys.should == default_handler
9
+ subject.convert_input_keys.should == default_handler
12
10
  end
13
11
  end
14
12
 
15
13
  context "when a custom input keys converter is set" do
16
14
  let(:custom_convert_input_keys) {lambda {|keys| keys}}
17
15
 
18
- before {RestModel::Configuration.convert_input_keys = custom_convert_input_keys}
16
+ before {subject.convert_input_keys = custom_convert_input_keys}
19
17
 
20
18
  it "returns custom key converter" do
21
- RestModel::Configuration.convert_input_keys.should == custom_convert_input_keys
19
+ subject.convert_input_keys.should == custom_convert_input_keys
22
20
  end
23
21
  end
24
22
  end
@@ -2,67 +2,43 @@ require 'spec_helper'
2
2
 
3
3
  describe RestModel::Association do
4
4
  describe "#initialize" do
5
- context "class_name" do
6
- context "when class_name option is passed" do
5
+ context "options[:class_name]" do
6
+ context "when it's passed" do
7
7
  subject do
8
8
  RestModel::Association.new(:login, class_name: :some_class)
9
9
  end
10
10
 
11
- it "sets passed class_name" do
11
+ it "sets class_name" do
12
12
  subject.instance_variable_get("@class_name").should == "SomeClass"
13
13
  end
14
14
  end
15
15
 
16
- context "when class_name option is not passed" do
16
+ context "when it isn't passed" do
17
17
  subject {RestModel::Association.new(:login)}
18
18
 
19
- it "sets default class_name" do
19
+ it "uses default class_name" do
20
20
  subject.instance_variable_get("@class_name").should == "Login"
21
21
  end
22
22
  end
23
23
  end
24
24
 
25
- context "many" do
26
- context "when many option is passed with true" do
27
- subject do
28
- RestModel::Association.new(:login, many: true)
29
- end
30
-
31
- it "returns false to one?" do
32
- subject.one?.should be_false
33
- end
34
-
35
- it "returns true to many?" do
36
- subject.many?.should be_true
37
- end
25
+ context "options[:many]" do
26
+ context "when it's true" do
27
+ subject {RestModel::Association.new(:login, many: true)}
28
+ its(:one?) {should be_false}
29
+ its(:many?) {should be_true}
38
30
  end
39
31
 
40
- context "when many option is passed with false" do
41
- subject do
42
- RestModel::Association.new(:login, many: false)
43
- end
44
-
45
- it "returns true to one?" do
46
- subject.one?.should be_true
47
- end
48
-
49
- it "returns false to many?" do
50
- subject.many?.should be_false
51
- end
32
+ context "when it's false" do
33
+ subject {RestModel::Association.new(:login, many: false)}
34
+ its(:one?) {should be_true}
35
+ its(:many?) {should be_false}
52
36
  end
53
37
 
54
- context "when many option is not passed" do
55
- subject do
56
- RestModel::Association.new(:login)
57
- end
58
-
59
- it "returns true to one?" do
60
- subject.one?.should be_true
61
- end
62
-
63
- it "returns false to many?" do
64
- subject.many?.should be_false
65
- end
38
+ context "when it isn't passed" do
39
+ subject {RestModel::Association.new(:login)}
40
+ its(:one?) {should be_true}
41
+ its(:many?) {should be_false}
66
42
  end
67
43
  end
68
44
  end
@@ -19,7 +19,7 @@ describe RestModel::Embeddable::Response do
19
19
 
20
20
  context "when this key shouldn't be visible on resource" do
21
21
  it "returns an empty hash" do
22
- subject.should_receive(:visible?).and_return false
22
+ subject.should_receive(:visible?) {false}
23
23
  subject.to_resource(example).should == {}
24
24
  end
25
25
  end
@@ -4,4 +4,27 @@ describe RestModel::Embeddable do
4
4
  it "is a relation" do
5
5
  RestModel::Embeddable.superclass.should == RestModel::Association
6
6
  end
7
+
8
+ describe "#raw?" do
9
+ context "when class_name is array" do
10
+ subject {RestModel::Embeddable.new(:example, class_name: :array)}
11
+ its(:raw?) {should be_true}
12
+ end
13
+
14
+ context "when class_name is hash" do
15
+ subject {RestModel::Embeddable.new(:example, class_name: :hash)}
16
+ its(:raw?) {should be_true}
17
+ end
18
+
19
+ context "when class_name isn't hash nor array" do
20
+ subject {RestModel::Embeddable.new(:example)}
21
+ its(:raw?) {should be_false}
22
+ end
23
+
24
+ context "when fields are defined" do
25
+ subject {RestModel::Embeddable.new(:example, fields: %w(a b c))}
26
+ its(:raw?) {should be_true}
27
+ its(:fields) {should == %w(a b c)}
28
+ end
29
+ end
7
30
  end
@@ -1,22 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RestModel::Property::Response do
4
- class Customer
4
+ class User
5
5
  attr_accessor :login
6
6
  end
7
7
 
8
8
  subject {RestModel::Property.new(:login)}
9
9
 
10
10
  it "returns a pair with property name and value" do
11
- customer = Customer.new.tap {|c| c.login = "jackiechan2010"}
12
- subject.to_resource(customer).should == {login: "jackiechan2010"}
11
+ user = User.new.tap {|u| u.login = "jackiechan2010"}
12
+ subject.to_resource(user).should == {login: "jackiechan2010"}
13
13
  end
14
14
 
15
15
  context "when this key shouldn't be visible on resource" do
16
16
  it "returns an empty hash" do
17
- subject.should_receive(:visible?).and_return false
18
- customer = Customer.new.tap {|c| c.login = "jackiechan2010"}
19
- subject.to_resource(customer).should == {}
17
+ subject.should_receive(:visible?) {false}
18
+ user = User.new.tap {|u| u.login = "jackiechan2010"}
19
+ subject.to_resource(user).should == {}
20
20
  end
21
21
  end
22
22
  end
@@ -7,11 +7,11 @@ describe RestModel::Property::Retriever do
7
7
  let(:serializer_mock) {mock :serializer}
8
8
 
9
9
  before do
10
- subject.stub!(:serializer).and_return serializer_mock
10
+ subject.stub!(:serializer) {serializer_mock}
11
11
  end
12
12
 
13
13
  it "tries to serialize value" do
14
- serializer_mock.should_receive(:serialize).with(item[:login]).and_return(item[:login])
14
+ serializer_mock.should_receive(:serialize).with(item[:login], instance_of(Hash)) {item[:login]}
15
15
  subject.from_source(item)
16
16
  end
17
17
 
@@ -11,7 +11,7 @@ describe RestModel::Response do
11
11
  context "#to_resource" do
12
12
  context "when the key shouldn't be visible on resource" do
13
13
  it "returns an empty hash" do
14
- subject.should_receive(:visible?).and_return false
14
+ subject.should_receive(:visible?) {false}
15
15
  subject.to_resource(example).should == {}
16
16
  end
17
17
  end
@@ -49,6 +49,31 @@ describe RestModel::Response do
49
49
  it_behaves_like "a relation"
50
50
  end
51
51
 
52
+ context "when has one (with :href option)" do
53
+ before do
54
+ class ExampleChild < RestModel
55
+ id
56
+ belongs_to :example
57
+ end
58
+
59
+ class Example < RestModel
60
+ id
61
+ has_one :example_child, href: proc {example_child_link}
62
+
63
+ def example_child_link
64
+ "http://example.com/examples/#{id}/example_custom_child"
65
+ end
66
+ end
67
+ end
68
+
69
+ subject {Example.keys[1]}
70
+
71
+ let(:example) {Example.new(id: 100)}
72
+ let(:result) {{rel: :example_child, href: "http://example.com/examples/100/example_custom_child"}}
73
+
74
+ it_behaves_like "a relation"
75
+ end
76
+
52
77
  context "when has many" do
53
78
  before do
54
79
  class ExampleChild < RestModel
@@ -70,6 +95,31 @@ describe RestModel::Response do
70
95
  it_behaves_like "a relation"
71
96
  end
72
97
 
98
+ context "when has many (with :href option)" do
99
+ before do
100
+ class ExampleChild < RestModel
101
+ id
102
+ belongs_to :example
103
+ end
104
+
105
+ class Example < RestModel
106
+ id
107
+ has_many :example_children, href: proc {example_child_link}
108
+
109
+ def example_child_link
110
+ "http://example.com/api/examples/#{id}/example_custom_children"
111
+ end
112
+ end
113
+ end
114
+
115
+ subject {Example.keys[1]}
116
+
117
+ let(:example) {Example.new(id: 200)}
118
+ let(:result) {{rel: :example_children, href: "http://example.com/api/examples/200/example_custom_children"}}
119
+
120
+ it_behaves_like "a relation"
121
+ end
122
+
73
123
  context "when belongs to one" do
74
124
  before do
75
125
  class ExampleChild < RestModel
@@ -91,6 +141,52 @@ describe RestModel::Response do
91
141
  it_behaves_like "a relation"
92
142
  end
93
143
 
144
+ context "when belongs to one (with :href option)" do
145
+ before do
146
+ class ExampleChild < RestModel
147
+ id
148
+ belongs_to :example, href: proc {example_link}
149
+
150
+ def example_link
151
+ "http://example.com/api/examples/#{example_id}"
152
+ end
153
+ end
154
+
155
+ class Example < RestModel
156
+ id
157
+ has_many :example_children
158
+ end
159
+ end
160
+
161
+ subject {ExampleChild.keys[1]}
162
+
163
+ let(:example) {ExampleChild.new(id: 200, example_id: 123)}
164
+ let(:result) {{rel: :example, href: "http://example.com/api/examples/123"}}
165
+
166
+ it_behaves_like "a relation"
167
+ end
168
+
169
+ context "escaped href" do
170
+ before do
171
+ class ExampleChild < RestModel
172
+ id
173
+ belongs_to :example
174
+ end
175
+
176
+ class Example < RestModel
177
+ id
178
+ has_many :example_children
179
+ end
180
+ end
181
+
182
+ subject {ExampleChild.keys[1]}
183
+
184
+ let(:example) {ExampleChild.new(id: 200, example_id: "Some Id")}
185
+ let(:result) {{rel: :example, href: "http://example.com/examples/Some%20Id"}}
186
+
187
+ it_behaves_like "a relation"
188
+ end
189
+
94
190
  context "when using forbidden key names" do
95
191
  [:resource_id, :resource].each do |forbidden_name|
96
192
  it "raises an exception for #{forbidden_name}" do
@@ -5,67 +5,28 @@ describe RestModel::Relation do
5
5
  RestModel::Relation.superclass.should == RestModel::Association
6
6
  end
7
7
 
8
- describe "#has?" do
8
+ describe "#has? and #belongs?" do
9
9
  context "when it has one resource" do
10
- subject do
11
- RestModel::Relation.new(:service, many: false, has: true)
12
- end
13
-
14
- it "returns true" do
15
- subject.has?.should be_true
16
- end
10
+ subject {RestModel::Relation.new(:service, many: false, has: true)}
11
+ its(:has?) {should be_true}
12
+ its(:belongs?) {should be_false}
17
13
  end
18
14
 
19
15
  context "when it has many resources" do
20
- subject do
21
- RestModel::Relation.new(:service, many: true, has: true)
22
- end
23
-
24
- it "returns true" do
25
- subject.has?.should be_true
26
- end
16
+ subject {RestModel::Relation.new(:service, many: true, has: true)}
17
+ its(:has?) {should be_true}
18
+ its(:belongs?) {should be_false}
27
19
  end
28
20
 
29
21
  context "when it belongs to a resource" do
30
- subject do
31
- RestModel::Relation.new(:service, many: false, has: false)
32
- end
33
-
34
- it "returns true" do
35
- subject.has?.should be_false
36
- end
22
+ subject {RestModel::Relation.new(:service, many: false, has: false)}
23
+ its(:has?) {should be_false}
24
+ its(:belongs?) {should be_true}
37
25
  end
38
26
  end
39
27
 
40
- describe "#belongs?" do
41
- context "when it belongs to a resource" do
42
- subject do
43
- RestModel::Relation.new(:service, many: false, has: false)
44
- end
45
-
46
- it "returns true" do
47
- subject.belongs?.should be_true
48
- end
49
- end
50
-
51
- context "when it has one resource" do
52
- subject do
53
- RestModel::Relation.new(:service, many: false, has: true)
54
- end
55
-
56
- it "returns true" do
57
- subject.belongs?.should be_false
58
- end
59
- end
60
-
61
- context "when it has many resources" do
62
- subject do
63
- RestModel::Relation.new(:service, many: true, has: true)
64
- end
65
-
66
- it "returns true" do
67
- subject.belongs?.should be_false
68
- end
69
- end
28
+ context "#relation?" do
29
+ subject {RestModel::Relation.new(:example)}
30
+ its(:relation?) {should be_true}
70
31
  end
71
32
  end
@@ -19,14 +19,14 @@ describe RestModel::Key do
19
19
  describe "#visible?" do
20
20
  context "when :visible option was defined" do
21
21
  context "and :if option was defined with false" do
22
- subject {RestModel::Property.new(name, {if: proc {false}, visible: true})}
22
+ subject {RestModel::Property.new(name, if: proc {false}, visible: true)}
23
23
  it "return false even when visible is true" do
24
24
  subject.visible?(nil).should be_false
25
25
  end
26
26
  end
27
27
 
28
28
  context "and it evaluates to false" do
29
- subject {RestModel::Property.new(name, {visible: false})}
29
+ subject {RestModel::Property.new(name, visible: false)}
30
30
 
31
31
  it "returns false" do
32
32
  subject.visible?(nil).should be_false
@@ -34,7 +34,7 @@ describe RestModel::Key do
34
34
  end
35
35
 
36
36
  context "and it evaluates to true" do
37
- subject {RestModel::Property.new(name, {visible: true})}
37
+ subject {RestModel::Property.new(name, visible: true)}
38
38
 
39
39
  it "returns true" do
40
40
  subject.visible?(nil).should be_true
@@ -43,21 +43,21 @@ describe RestModel::Key do
43
43
 
44
44
  context "with a proc" do
45
45
  context "and it evaluates true" do
46
- subject {RestModel::Property.new(name, {visible: proc {true}})}
46
+ subject {RestModel::Property.new(name, visible: proc {true})}
47
47
  it "returns true" do
48
48
  subject.visible?("a").should be_true
49
49
  end
50
50
  end
51
51
 
52
52
  context "and it evaluates false" do
53
- subject {RestModel::Property.new(name, {visible: proc {false}})}
53
+ subject {RestModel::Property.new(name, visible: proc {false})}
54
54
  it "returns false" do
55
55
  subject.visible?("a").should be_false
56
56
  end
57
57
  end
58
58
 
59
59
  context "and it depends on resource instance" do
60
- subject {RestModel::Property.new(name, {visible: proc {show}})}
60
+ subject {RestModel::Property.new(name, visible: proc {show})}
61
61
 
62
62
  it "uses it" do
63
63
  resource = OpenStruct.new
@@ -72,7 +72,7 @@ describe RestModel::Key do
72
72
  describe "#present?" do
73
73
  context "when :if option was defined with a proc" do
74
74
  context "and it evaluates to false" do
75
- subject {RestModel::Property.new(name, {if: proc {false}})}
75
+ subject {RestModel::Property.new(name, if: proc {false})}
76
76
 
77
77
  it "returns false" do
78
78
  subject.present?(nil).should be_false
@@ -80,7 +80,7 @@ describe RestModel::Key do
80
80
  end
81
81
 
82
82
  context "and it evaluates to true" do
83
- subject {RestModel::Property.new(name, {if: proc {true}})}
83
+ subject {RestModel::Property.new(name, if: proc {true})}
84
84
 
85
85
  it "returns true" do
86
86
  subject.present?(nil).should be_true
@@ -88,7 +88,7 @@ describe RestModel::Key do
88
88
  end
89
89
 
90
90
  context "and it depends on resource instance" do
91
- subject {RestModel::Property.new(name, {if: proc {show}})}
91
+ subject {RestModel::Property.new(name, if: proc {show})}
92
92
 
93
93
  it "uses it" do
94
94
  resource = OpenStruct.new
@@ -98,4 +98,8 @@ describe RestModel::Key do
98
98
  end
99
99
  end
100
100
  end
101
+
102
+ describe "#relation?" do
103
+ its(:relation?) {should be_false}
104
+ end
101
105
  end
@@ -12,6 +12,14 @@ describe RestModel::Response do
12
12
  property :street
13
13
  property :city
14
14
  end
15
+
16
+ class SummarizeExample < RestModel
17
+ id
18
+ property :name
19
+ property :login
20
+
21
+ summarizes :id, :name, :login
22
+ end
15
23
  end
16
24
 
17
25
  let(:input) do
@@ -34,11 +42,41 @@ describe RestModel::Response do
34
42
  end
35
43
 
36
44
  context "when a list of resources is received" do
37
- it "returns some resources in an entries array" do
38
- model = 3.times.map {Example.parse(input).first}
39
- result = {entries: 3.times.map {input}}
40
- Example.normalize(model).with_indifferent_access.should == result.with_indifferent_access
45
+ context "with sumarize options" do
46
+ it "returns some resources in an entries array" do
47
+ model = 3.times.map {Example.parse(input).first}
48
+ result = {entries: 3.times.map {input}}
49
+ Example.normalize(model).with_indifferent_access.should == result.with_indifferent_access
50
+ end
51
+ end
52
+
53
+ context "without sumarize options" do
54
+ let(:input) do
55
+ {
56
+ id: "Escape This",
57
+ name: "My name is",
58
+ login: "my_login"
59
+ }
60
+ end
61
+
62
+ let(:expected) do
63
+ {
64
+ entries: [
65
+ {
66
+ id: "Escape This",
67
+ name: "My name is",
68
+ login: "my_login",
69
+ href: "http://example.com/summarize_examples/Escape%20This"
70
+ }
71
+ ]
72
+ }
73
+ end
74
+
75
+ it "returns some resources in an entries array" do
76
+ model = SummarizeExample.parse(input)
77
+ SummarizeExample.normalize(model).with_indifferent_access.should == expected.with_indifferent_access
78
+ end
41
79
  end
42
80
  end
43
81
  end
44
- end
82
+ end
@@ -5,6 +5,10 @@ describe RestModel::Serialization::Date do
5
5
  subject.class.serialize('2011-07-01').should == Date.new(2011, 07, 01)
6
6
  end
7
7
 
8
+ it "desserializes to date respecting the provided format" do
9
+ subject.class.desserialize(Date.new(2038, 1, 19), format: "%a %b %d %Y").should == "Tue Jan 19 2038"
10
+ end
11
+
8
12
  context "when an invalid value is serialized" do
9
13
  it "raises an error" do
10
14
  expect {subject.class.serialize("not a date")}.to raise_error
@@ -5,6 +5,10 @@ describe RestModel::Serialization::DateTime do
5
5
  subject.class.serialize('2011-07-01T10:20:30').should == DateTime.new(2011, 07, 01, 10, 20, 30)
6
6
  end
7
7
 
8
+ it "desserializes to date time respecting the provided format" do
9
+ subject.class.desserialize(DateTime.new(2012, 12, 31, 12, 0, 0), format: "%a %b %d %H:%M:%S %Y").should == "Mon Dec 31 12:00:00 2012"
10
+ end
11
+
8
12
  context "when an invalid value is serialized" do
9
13
  it "raises an error" do
10
14
  expect {subject.class.serialize("not a date time")}.to raise_error
@@ -1,10 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe RestModel::Serialization::Integer do
4
+ it "adds leading zeros from options while desserializing" do
5
+ subject.class.desserialize('1200', padding_zeros: 12).should == "000000001200"
6
+ end
7
+
4
8
  it "converts to integer" do
5
9
  subject.class.serialize('1200').should == 1200
6
10
  end
7
11
 
12
+ it "converts negative number to negative integer" do
13
+ subject.class.serialize('-1').should == -1
14
+ end
15
+
8
16
  context "when an invalid value is serialized" do
9
17
  it "raises an error" do
10
18
  expect {subject.class.serialize("not an integer")}.to raise_error
@@ -1,6 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
- module Upcasing
3
+ module InputKeysConverterStrategy
4
4
  def self.call(keys)
5
5
  keys.map {|key| key.to_s.upcase}
6
6
  end
@@ -21,7 +21,7 @@ describe RestModel::Source::Path do
21
21
  end
22
22
 
23
23
  context "and there is a custom keys input converter" do
24
- subject {RestModel::Key.new(:name, convert_input_keys: Upcasing)}
24
+ subject {RestModel::Key.new(:name, convert_input_keys: InputKeysConverterStrategy)}
25
25
  let(:path) {['NAME']}
26
26
  it_behaves_like "an input path"
27
27
  end
@@ -53,7 +53,7 @@ describe RestModel::Source::Path do
53
53
  end
54
54
 
55
55
  context "and there is a custom keys input converter" do
56
- let(:options) {{start_key: 'yay.upcase.path', convert_input_keys: Upcasing}}
56
+ let(:options) {{start_key: 'yay.upcase.path', convert_input_keys: InputKeysConverterStrategy}}
57
57
  subject {RestModel::Key.new(:name, options)}
58
58
  let(:path) {['YAY', 'UPCASE', 'PATH']}
59
59
  it_behaves_like "an input path"
@@ -7,7 +7,7 @@ describe RestModel::Source::Retriever do
7
7
  property :login
8
8
  end
9
9
 
10
- models = Example.parse({login: 'jackiechan2010'})
10
+ models = Example.parse(login: 'jackiechan2010')
11
11
  models.should be_an(Array)
12
12
  models.first.login.should == 'jackiechan2010'
13
13
  end
@@ -17,7 +17,7 @@ describe RestModel::Source::Retriever do
17
17
  property :login, field: :customer_login
18
18
  end
19
19
 
20
- models = Example.parse({customer_login: 'jackiechan2010'})
20
+ models = Example.parse(customer_login: 'jackiechan2010')
21
21
  models.should be_an(Array)
22
22
  models.first.login.should == 'jackiechan2010'
23
23
  end
@@ -31,12 +31,12 @@ describe RestModel::Source::Retriever do
31
31
  end
32
32
 
33
33
  it "returns true when value is 'X'" do
34
- models = Example.parse({can_merge: 'X'})
34
+ models = Example.parse(can_merge: 'X')
35
35
  models.first.can_merge.should be_true
36
36
  end
37
37
 
38
38
  it "returns false when value isn't 'X'" do
39
- models = Example.parse({can_merge: ''})
39
+ models = Example.parse(can_merge: '')
40
40
  models.first.can_merge.should be_false
41
41
  end
42
42
  end
@@ -47,7 +47,7 @@ describe RestModel::Source::Retriever do
47
47
  property :issue_date, type: Date
48
48
  end
49
49
 
50
- models = Example.parse({issue_date: '2011-01-01'})
50
+ models = Example.parse(issue_date: '2011-01-01')
51
51
  models.first.issue_date.should == Date.parse('2011-01-01')
52
52
  end
53
53
  end
@@ -58,7 +58,7 @@ describe RestModel::Source::Retriever do
58
58
  property :amount, type: Float
59
59
  end
60
60
 
61
- models = Example.parse({amount: '1234.5'})
61
+ models = Example.parse(amount: '1234.5')
62
62
  models.first.amount.should == 1234.5
63
63
  end
64
64
  end
@@ -72,20 +72,20 @@ describe RestModel::Source::Retriever do
72
72
  end
73
73
 
74
74
  it "returns key when value was mapped" do
75
- models = Example.from_source!({status: '02'})
75
+ models = Example.from_source!(status: '02')
76
76
  models.first.status.should == :unpaid
77
77
  end
78
78
 
79
79
  context "when calling from_source" do
80
80
  it "returns nil when value wasn't mapped" do
81
- models = Example.from_source({status: '03'})
81
+ models = Example.from_source(status: '03')
82
82
  models.first.status.should be_nil
83
83
  end
84
84
  end
85
85
 
86
86
  context "when calling from_source!" do
87
87
  it "fails when value wasn't mapped" do
88
- expect {Example.from_source!({status: '03'})}.to raise_error
88
+ expect {Example.from_source!(status: '03')}.to raise_error
89
89
  end
90
90
  end
91
91
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,33 +11,43 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-04-26 00:00:00.000000000Z
14
+ date: 2013-05-02 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
18
- requirement: &70119449382520 !ruby/object:Gem::Requirement
18
+ requirement: !ruby/object:Gem::Requirement
19
19
  none: false
20
20
  requirements:
21
21
  - - ~>
22
22
  - !ruby/object:Gem::Version
23
- version: '3.0'
23
+ version: '3.2'
24
24
  type: :runtime
25
25
  prerelease: false
26
- version_requirements: *70119449382520
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ~>
30
+ - !ruby/object:Gem::Version
31
+ version: '3.2'
27
32
  - !ruby/object:Gem::Dependency
28
33
  name: i18n
29
- requirement: &70119449382020 !ruby/object:Gem::Requirement
34
+ requirement: !ruby/object:Gem::Requirement
30
35
  none: false
31
36
  requirements:
32
37
  - - ! '>='
33
38
  - !ruby/object:Gem::Version
34
- version: '0.5'
39
+ version: '0.6'
35
40
  type: :runtime
36
41
  prerelease: false
37
- version_requirements: *70119449382020
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0.6'
38
48
  - !ruby/object:Gem::Dependency
39
49
  name: rspec
40
- requirement: &70119449381560 !ruby/object:Gem::Requirement
50
+ requirement: !ruby/object:Gem::Requirement
41
51
  none: false
42
52
  requirements:
43
53
  - - ~>
@@ -45,40 +55,28 @@ dependencies:
45
55
  version: '2.6'
46
56
  type: :development
47
57
  prerelease: false
48
- version_requirements: *70119449381560
49
- - !ruby/object:Gem::Dependency
50
- name: guard
51
- requirement: &70119443530980 !ruby/object:Gem::Requirement
58
+ version_requirements: !ruby/object:Gem::Requirement
52
59
  none: false
53
60
  requirements:
54
61
  - - ~>
55
62
  - !ruby/object:Gem::Version
56
- version: '0.5'
57
- type: :development
58
- prerelease: false
59
- version_requirements: *70119443530980
63
+ version: '2.6'
60
64
  - !ruby/object:Gem::Dependency
61
- name: guard-rspec
62
- requirement: &70119443530520 !ruby/object:Gem::Requirement
65
+ name: rake
66
+ requirement: !ruby/object:Gem::Requirement
63
67
  none: false
64
68
  requirements:
65
- - - ~>
69
+ - - ! '>='
66
70
  - !ruby/object:Gem::Version
67
- version: '0.4'
71
+ version: '0'
68
72
  type: :development
69
73
  prerelease: false
70
- version_requirements: *70119443530520
71
- - !ruby/object:Gem::Dependency
72
- name: growl
73
- requirement: &70119443530060 !ruby/object:Gem::Requirement
74
+ version_requirements: !ruby/object:Gem::Requirement
74
75
  none: false
75
76
  requirements:
76
- - - ~>
77
+ - - ! '>='
77
78
  - !ruby/object:Gem::Version
78
- version: '1.0'
79
- type: :development
80
- prerelease: false
81
- version_requirements: *70119443530060
79
+ version: '0'
82
80
  description: ''
83
81
  email:
84
82
  - victorcrodrigues@gmail.com
@@ -89,8 +87,8 @@ extensions: []
89
87
  extra_rdoc_files: []
90
88
  files:
91
89
  - .gitignore
90
+ - .travis.yml
92
91
  - Gemfile
93
- - Guardfile
94
92
  - README.md
95
93
  - Rakefile
96
94
  - examples/all.rb
@@ -245,46 +243,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
245
243
  version: '0'
246
244
  requirements: []
247
245
  rubyforge_project:
248
- rubygems_version: 1.8.15
246
+ rubygems_version: 1.8.23
249
247
  signing_key:
250
248
  specification_version: 3
251
249
  summary: ''
252
- test_files:
253
- - spec/integration/belongs_to_spec.rb
254
- - spec/integration/embeds_many_spec.rb
255
- - spec/integration/embeds_one_spec.rb
256
- - spec/integration/has_many_spec.rb
257
- - spec/integration/has_one_spec.rb
258
- - spec/integration/property_spec.rb
259
- - spec/integration/summarization_spec.rb
260
- - spec/integration/to_source_spec.rb
261
- - spec/integration/update_attributes_spec.rb
262
- - spec/integration/validations_spec.rb
263
- - spec/spec_helper.rb
264
- - spec/support/examples.rb
265
- - spec/support/out.rb
266
- - spec/support/shared_examples.rb
267
- - spec/unit/configuration_spec.rb
268
- - spec/unit/key/association_spec.rb
269
- - spec/unit/key/embeddable/builder_spec.rb
270
- - spec/unit/key/embeddable/response_spec.rb
271
- - spec/unit/key/embeddable/retriever_spec.rb
272
- - spec/unit/key/embeddable_spec.rb
273
- - spec/unit/key/property/builder_spec.rb
274
- - spec/unit/key/property/response_spec.rb
275
- - spec/unit/key/property/retriever_spec.rb
276
- - spec/unit/key/property_spec.rb
277
- - spec/unit/key/relation/builder_spec.rb
278
- - spec/unit/key/relation/response_spec.rb
279
- - spec/unit/key/relation_spec.rb
280
- - spec/unit/key_spec.rb
281
- - spec/unit/response_spec.rb
282
- - spec/unit/rest_model_spec.rb
283
- - spec/unit/serialization/boolean_spec.rb
284
- - spec/unit/serialization/date_spec.rb
285
- - spec/unit/serialization/date_time_spec.rb
286
- - spec/unit/serialization/float_spec.rb
287
- - spec/unit/serialization/integer_spec.rb
288
- - spec/unit/serialization/string_spec.rb
289
- - spec/unit/source/path_spec.rb
290
- - spec/unit/source/retriever_spec.rb
250
+ test_files: []
data/Guardfile DELETED
@@ -1,7 +0,0 @@
1
- guard 'rspec', cli: '--color' do
2
- watch(%r{spec/spec_helper.rb}) {"spec"}
3
- watch(%r{^config\/(.*\/)*.*\.rb$}) {"spec"}
4
-
5
- watch(%r{^spec/.+_spec\.rb})
6
- watch(%r{^lib/(.+)\.rb}) {|m| "spec/#{m[1]}_spec.rb"}
7
- end