rest_model 0.2.1 → 0.2.3

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