rest_model 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +2 -0
  3. data/Guardfile +7 -0
  4. data/README.md +237 -0
  5. data/Rakefile +2 -0
  6. data/examples/all.rb +12 -0
  7. data/examples/embeds_many/invisible.rb +16 -0
  8. data/examples/embeds_many/simple.rb +13 -0
  9. data/examples/embeds_many/with_array.rb +10 -0
  10. data/examples/embeds_many/with_class_name.rb +13 -0
  11. data/examples/embeds_many/with_fields.rb +9 -0
  12. data/examples/embeds_many/with_if.rb +16 -0
  13. data/examples/embeds_many/with_nil_value.rb +12 -0
  14. data/examples/embeds_many/with_start_key.rb +13 -0
  15. data/examples/embeds_one/flattened.rb +12 -0
  16. data/examples/embeds_one/simple.rb +12 -0
  17. data/examples/embeds_one/with_class_name.rb +12 -0
  18. data/examples/embeds_one/with_if.rb +16 -0
  19. data/examples/embeds_one/with_start_key.rb +12 -0
  20. data/examples/has_many/simple.rb +28 -0
  21. data/examples/helper.rb +9 -0
  22. data/examples/initialize/embeds_many.rb +25 -0
  23. data/examples/initialize/embeds_many_array.rb +9 -0
  24. data/examples/initialize/embeds_one.rb +19 -0
  25. data/examples/initialize/simple.rb +8 -0
  26. data/examples/properties/array_serialization.rb +8 -0
  27. data/examples/properties/collections.rb +11 -0
  28. data/examples/properties/simple.rb +8 -0
  29. data/examples/properties/with_field.rb +8 -0
  30. data/examples/properties/with_field_path.rb +8 -0
  31. data/examples/properties/with_id.rb +8 -0
  32. data/examples/properties/with_if.rb +21 -0
  33. data/examples/properties/with_key_converter.rb +18 -0
  34. data/examples/properties/with_two_key_converters.rb +27 -0
  35. data/examples/properties/with_values.rb +10 -0
  36. data/examples/summarization/simple.rb +21 -0
  37. data/examples/to_input/embeds_many.rb +25 -0
  38. data/examples/to_input/embeds_many_without_key.rb +31 -0
  39. data/examples/to_input/embeds_one.rb +13 -0
  40. data/examples/to_input/embeds_one_without_key.rb +23 -0
  41. data/examples/to_input/flattened.rb +12 -0
  42. data/examples/to_input/serializables.rb +19 -0
  43. data/examples/to_input/simple.rb +8 -0
  44. data/examples/to_input/with_field.rb +8 -0
  45. data/examples/to_input/with_field_path.rb +8 -0
  46. data/examples/to_input/with_fields.rb +8 -0
  47. data/examples/to_input/without_key.rb +11 -0
  48. data/examples/to_input/without_nil.rb +11 -0
  49. data/lib/rest_model/configuration.rb +45 -0
  50. data/lib/rest_model/key/association.rb +42 -0
  51. data/lib/rest_model/key/builder.rb +30 -0
  52. data/lib/rest_model/key/embeddable/builder.rb +19 -0
  53. data/lib/rest_model/key/embeddable/response.rb +25 -0
  54. data/lib/rest_model/key/embeddable/retriever.rb +20 -0
  55. data/lib/rest_model/key/embeddable/sender.rb +41 -0
  56. data/lib/rest_model/key/embeddable.rb +29 -0
  57. data/lib/rest_model/key/href/response.rb +10 -0
  58. data/lib/rest_model/key/href.rb +10 -0
  59. data/lib/rest_model/key/property/builder.rb +27 -0
  60. data/lib/rest_model/key/property/response.rb +9 -0
  61. data/lib/rest_model/key/property/retriever.rb +24 -0
  62. data/lib/rest_model/key/property/sender.rb +41 -0
  63. data/lib/rest_model/key/property.rb +22 -0
  64. data/lib/rest_model/key/relation/builder.rb +24 -0
  65. data/lib/rest_model/key/relation/response.rb +38 -0
  66. data/lib/rest_model/key/relation.rb +23 -0
  67. data/lib/rest_model/key.rb +44 -0
  68. data/lib/rest_model/response.rb +42 -0
  69. data/lib/rest_model/serialization/boolean.rb +48 -0
  70. data/lib/rest_model/serialization/date.rb +19 -0
  71. data/lib/rest_model/serialization/enumerable.rb +15 -0
  72. data/lib/rest_model/serialization/float.rb +17 -0
  73. data/lib/rest_model/serialization/integer.rb +17 -0
  74. data/lib/rest_model/serialization/string.rb +13 -0
  75. data/lib/rest_model/source/path.rb +25 -0
  76. data/lib/rest_model/source/retriever.rb +48 -0
  77. data/lib/rest_model/source/sender.rb +38 -0
  78. data/lib/rest_model/version.rb +3 -0
  79. data/lib/rest_model.rb +101 -0
  80. data/rest_model.gemspec +26 -0
  81. data/spec/.DS_Store +0 -0
  82. data/spec/integration/embeds_many_spec.rb +57 -0
  83. data/spec/integration/embeds_one_spec.rb +41 -0
  84. data/spec/integration/has_many_spec.rb +27 -0
  85. data/spec/integration/property_spec.rb +69 -0
  86. data/spec/integration/summarization_spec.rb +12 -0
  87. data/spec/spec_helper.rb +26 -0
  88. data/spec/support/examples.rb +29 -0
  89. data/spec/support/out.rb +17 -0
  90. data/spec/support/shared_examples.rb +20 -0
  91. data/spec/unit/configuration_spec.rb +24 -0
  92. data/spec/unit/key/association_spec.rb +69 -0
  93. data/spec/unit/key/embeddable/builder_spec.rb +26 -0
  94. data/spec/unit/key/embeddable/response_spec.rb +55 -0
  95. data/spec/unit/key/embeddable/retriever_spec.rb +38 -0
  96. data/spec/unit/key/embeddable_spec.rb +7 -0
  97. data/spec/unit/key/property/builder_spec.rb +154 -0
  98. data/spec/unit/key/property/response_spec.rb +22 -0
  99. data/spec/unit/key/property/retriever_spec.rb +31 -0
  100. data/spec/unit/key/property_spec.rb +39 -0
  101. data/spec/unit/key/relation/builder_spec.rb +53 -0
  102. data/spec/unit/key/relation/response_spec.rb +105 -0
  103. data/spec/unit/key/relation_spec.rb +71 -0
  104. data/spec/unit/key_spec.rb +101 -0
  105. data/spec/unit/response_spec.rb +44 -0
  106. data/spec/unit/rest_model_spec.rb +46 -0
  107. data/spec/unit/serialization/boolean_spec.rb +25 -0
  108. data/spec/unit/serialization/date_spec.rb +13 -0
  109. data/spec/unit/serialization/float_spec.rb +13 -0
  110. data/spec/unit/serialization/integer_spec.rb +13 -0
  111. data/spec/unit/serialization/string_spec.rb +11 -0
  112. data/spec/unit/source/path_spec.rb +62 -0
  113. data/spec/unit/source/retriever_spec.rb +85 -0
  114. metadata +260 -0
@@ -0,0 +1,24 @@
1
+ class RestModel
2
+ class Relation
3
+ module Builder
4
+ def relation(name, options = {})
5
+ key Relation.new(name, options)
6
+ end
7
+
8
+ def has_one(name, options = {})
9
+ options.merge!(many: false, has: true)
10
+ relation(name, options)
11
+ end
12
+
13
+ def has_many(name, options = {})
14
+ options.merge!(many: true, has: true)
15
+ relation(name, options)
16
+ end
17
+
18
+ def belongs_to(name, options = {})
19
+ options.merge!(many: false, has: false)
20
+ relation(name, options)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,38 @@
1
+ class RestModel
2
+ class Relation
3
+ module Response
4
+ def to_resource(parent)
5
+ included = parent.__send__(name)
6
+ return {} unless visible?(parent) and included
7
+ {name => resource_from_included(included)}
8
+ end
9
+
10
+ def to_relation(parent)
11
+ {rel: name, href: href(parent)}
12
+ end
13
+
14
+ private
15
+
16
+ def relation_name(parent)
17
+ relation = parent.class.relations.find do |key|
18
+ key.resource_class == self.resource_class
19
+ end
20
+ relation.name or fail
21
+ end
22
+
23
+ def resource_from_included(included)
24
+ options = {root: false}
25
+ one? ?
26
+ included.resource(options)
27
+ : included.map {|r| r.resource(options)}
28
+ end
29
+
30
+ def href(parent)
31
+ id_key = parent.class.id_key.name
32
+ has? ?
33
+ "#{RestModel::Configuration.host}/#{parent.class.resource_name}/#{parent.send(id_key)}/#{relation_name(parent)}"
34
+ : "#{RestModel::Configuration.host}/#{relation_name(parent).to_s.pluralize}/#{parent.send(id_key)}/#{parent.class.resource_name}"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ class RestModel
2
+ class Relation < Association
3
+ autoload :Response, "rest_model/key/relation/response"
4
+ include Response
5
+
6
+ def initialize(name, options = {})
7
+ super
8
+ @has = options.fetch(:has, false)
9
+ end
10
+
11
+ def has?
12
+ @has
13
+ end
14
+
15
+ def belongs?
16
+ !has?
17
+ end
18
+
19
+ def parse(value, resource = nil)
20
+ nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ class RestModel
2
+ class Key
3
+ attr_accessor :name, :model, :options, :summarize
4
+
5
+ def initialize(name, options = {})
6
+ @name = name
7
+ @options = options
8
+ end
9
+
10
+ def convert_input_keys
11
+ options.fetch(:convert_input_keys, model.try(:convert_input_keys) ||
12
+ RestModel::Configuration.convert_input_keys)
13
+ end
14
+
15
+ def source_path
16
+ return @source_path.clone if @source_path
17
+
18
+ @source_path = Source::Path.resolve(options, convert_input_keys)
19
+
20
+ if @source_path.empty? and !root_path?
21
+ @source_path = convert_input_keys.call([name])
22
+ end
23
+
24
+ @source_path.clone
25
+ end
26
+
27
+ def root_path?
28
+ path_definition = options.slice(:start_key, :field)
29
+ path_definition.any? and path_definition.first[1].empty?
30
+ end
31
+
32
+ def present?(resource)
33
+ !options[:if] ? true : resource.instance_eval(&options[:if])
34
+ end
35
+
36
+ def visible?(resource)
37
+ !present?(resource) ? false : case visible = options[:visible]
38
+ when nil then true
39
+ when Proc then resource.instance_eval(&visible)
40
+ else visible
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,42 @@
1
+ class RestModel
2
+ module Response
3
+ extend ActiveSupport::Concern
4
+
5
+ def resource(options = {})
6
+ root = options.fetch(:root, true)
7
+
8
+ {}.tap do |resource|
9
+ resource_keys(options).inject(resource) do |buffer, key|
10
+ buffer.merge!(key.to_resource(self))
11
+ end
12
+
13
+ if root and self.class.relations.any? and !options[:summarize]
14
+ resource.merge!({link: link})
15
+ end
16
+ end
17
+ end
18
+
19
+ def link
20
+ self.class.relations.map {|key| key.to_relation(self)}
21
+ end
22
+
23
+ def resource_keys(options)
24
+ summarize?(options) ? self.class.summarized_keys + [Href.new]
25
+ : self.class.keys
26
+ end
27
+
28
+ def summarize?(options)
29
+ options[:summarize] and self.class.summarized_keys.any?
30
+ end
31
+
32
+ module ClassMethods
33
+ def normalize(model, options = {})
34
+ model.kind_of?(Enumerable) ?
35
+ {entries: model.map {|m| m.resource(options.merge(summarize: true))}}
36
+ : model.resource(options)
37
+ end
38
+
39
+ alias :resources :normalize
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,48 @@
1
+ class RestModel
2
+ module Serialization
3
+ class Boolean
4
+ MAPPINGS = {
5
+ true => true,
6
+ "true" => true,
7
+ "TRUE" => true,
8
+ "1" => true,
9
+ 1 => true,
10
+ 1.0 => true,
11
+ "x" => true,
12
+ "X" => true,
13
+ "t" => true,
14
+ "T" => true,
15
+ false => false,
16
+ "false" => false,
17
+ "FALSE" => false,
18
+ "0" => false,
19
+ 0 => false,
20
+ 0.0 => false,
21
+ "" => false,
22
+ " " => false,
23
+ "f" => false,
24
+ "F" => false,
25
+ nil => false
26
+ }.freeze
27
+
28
+ def self.serialize(value)
29
+ MAPPINGS[value].tap do |bool|
30
+ fail "value not serializable: #{value}" if bool.nil?
31
+ end
32
+ end
33
+
34
+ def self.desserialize(value)
35
+ fail unless boolean?(value)
36
+
37
+ value ? RestModel.configuration.true_value
38
+ : RestModel.configuration.false_value
39
+ end
40
+
41
+ private
42
+
43
+ def self.boolean?(value)
44
+ !!value == value
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,19 @@
1
+ class RestModel
2
+ module Serialization
3
+ class Date
4
+ def self.serialize(value)
5
+ ::Date.parse value
6
+ rescue ArgumentError
7
+ raise "value not serializable: #{value}"
8
+ end
9
+
10
+ def self.desserialize(value)
11
+ date = value.kind_of?(::Date) ? value : ::Date.parse(value)
12
+ format = RestModel.configuration.date_format
13
+ format ? date.strftime(format) : date.to_s
14
+ rescue ArgumentError
15
+ raise "value not desserializable: #{value}"
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ class RestModel
2
+ module Serialization
3
+ class Enumerable
4
+ def self.serialize(value)
5
+ fail "value not serializable: #{value}" unless value.kind_of?(::Enumerable)
6
+ value
7
+ end
8
+
9
+ def self.desserialize(value)
10
+ fail "value not desserializable: #{value}" unless value.kind_of?(::Enumerable)
11
+ value
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ class RestModel
2
+ module Serialization
3
+ class Float
4
+ def self.serialize(value)
5
+ Float(value)
6
+ rescue ArgumentError
7
+ raise "value not serializable: #{value}"
8
+ end
9
+
10
+ def self.desserialize(value)
11
+ Float(value)
12
+ rescue ArgumentError
13
+ raise "value not desserializable: #{value}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ class RestModel
2
+ module Serialization
3
+ class Integer
4
+ def self.serialize(value)
5
+ Integer(value)
6
+ rescue ArgumentError
7
+ raise "value not serializable: #{value}"
8
+ end
9
+
10
+ def self.desserialize(value)
11
+ Integer(value)
12
+ rescue ArgumentError
13
+ raise "value not desserializable: #{value}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ class RestModel
2
+ module Serialization
3
+ class String
4
+ def self.serialize(value)
5
+ value.nil? ? nil : value.to_s
6
+ end
7
+
8
+ def self.desserialize(value)
9
+ value.nil? ? nil : value.to_s
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
1
+ class RestModel
2
+ module Source
3
+ module Path
4
+ def self.resolve(options, convert_input_keys = Key::Converter::DefaultHandler)
5
+ convert_input_keys.call keys_for_path(custom_path(options))
6
+ end
7
+
8
+ private
9
+
10
+ def self.custom_path(options)
11
+ options.slice(:start_key, :field)
12
+ end
13
+
14
+ def self.keys_for_path(path)
15
+ return [] if path.empty?
16
+
17
+ if path.values.first.kind_of?(Symbol)
18
+ [path.values.first]
19
+ else
20
+ path.values.first.to_s.split('.')
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ class RestModel
2
+ module Source
3
+ module Retriever
4
+ def from_source!(input, options = {})
5
+ from_source(input, options.merge(fail: true))
6
+ end
7
+
8
+ def from_source(input, options = {})
9
+ entries = prepare_entries(input, options)
10
+
11
+ if entries.any? {|e| !e.kind_of?(Hash)}
12
+ fail "invalid input" if options[:fail]
13
+ return []
14
+ end
15
+
16
+ entries.collect do |item|
17
+ handle_item(item.with_indifferent_access, options)
18
+ end
19
+ end
20
+
21
+ alias :parse! :from_source!
22
+ alias :parse :from_source
23
+
24
+ private
25
+
26
+ def prepare_entries(input, options)
27
+ path = Source::Path.resolve(options, RestModel::Configuration.convert_input_keys)
28
+ Array.wrap digg(input, path)
29
+ end
30
+
31
+ def handle_item(item, options)
32
+ self.new.tap do |resource|
33
+ keys.each do |key|
34
+ begin
35
+ resource.__send__("#{key.name}=", key.from_source(item, resource)) if key.present?(resource)
36
+ rescue => exception
37
+ raise exception if options[:fail]
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def digg(input, path)
44
+ path.inject(input) {|buffer, key| buffer = buffer[key]}
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,38 @@
1
+ class RestModel
2
+ module Source
3
+ module Sender
4
+ def to_source!(options = {})
5
+ to_source(options.merge(fail: true))
6
+ end
7
+
8
+ def to_source(options = {})
9
+ source = {}
10
+ root_options = {without_nil: options[:without_nil], fail: options[:fail]}
11
+
12
+ keys_to_source(options).each do |key|
13
+ value = __send__(key.name)
14
+ key_options = options.fetch(key.name, {}).merge(root_options)
15
+ source.merge! key.to_source!(value, self, key_options)
16
+ end
17
+
18
+ source.with_indifferent_access
19
+ end
20
+
21
+ alias :to_input! :to_source!
22
+ alias :to_input :to_source
23
+
24
+ private
25
+
26
+ def keys_to_source(options)
27
+ self.class.keys.clone.tap do |keys|
28
+ keys.reject! {|k| k.kind_of?(Relation)}
29
+ keys.reject! {|k| Array(options[:without]).include?(k.name)}
30
+
31
+ keys.reject! do |key|
32
+ __send__(key.name).nil? and options[:without_nil]
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,3 @@
1
+ class RestModel
2
+ VERSION = "0.1.0"
3
+ end
data/lib/rest_model.rb ADDED
@@ -0,0 +1,101 @@
1
+ require "date"
2
+ require "active_support/inflector"
3
+ require "active_support/concern"
4
+ require "active_support/core_ext/class/attribute_accessors"
5
+ require "active_support/core_ext/object/try"
6
+ require "active_support/core_ext/array/wrap"
7
+ require "active_support/core_ext/hash/slice"
8
+ require "active_support/core_ext/hash/indifferent_access"
9
+
10
+ require "rest_model/source/path"
11
+ require "rest_model/source/retriever"
12
+ require "rest_model/source/sender"
13
+ require "rest_model/response"
14
+ require "rest_model/serialization/boolean"
15
+ require "rest_model/serialization/date"
16
+ require "rest_model/serialization/enumerable"
17
+ require "rest_model/serialization/float"
18
+ require "rest_model/serialization/integer"
19
+ require "rest_model/serialization/string"
20
+ require "rest_model/key"
21
+ require "rest_model/key/property"
22
+ require "rest_model/key/property/builder"
23
+ require "rest_model/key/association"
24
+ require "rest_model/key/relation"
25
+ require "rest_model/key/relation/builder"
26
+ require "rest_model/key/embeddable"
27
+ require "rest_model/key/embeddable/builder"
28
+ require "rest_model/key/href"
29
+ require "rest_model/key/builder"
30
+ require "rest_model/configuration"
31
+
32
+ class RestModel
33
+ extend Key::Builder
34
+ extend Source::Retriever
35
+ include Source::Sender
36
+ include Response
37
+ include Serialization
38
+
39
+ cattr_accessor :id_key
40
+ cattr_writer :resource_name
41
+
42
+ def initialize(attrs = {})
43
+ return if attrs.nil? or attrs.empty?
44
+
45
+ attrs = attrs.with_indifferent_access
46
+
47
+ self.class.keys.each do |key|
48
+ __send__("#{key.name}=", key.from_hash(attrs[key.name])) if key.present?(self)
49
+ end
50
+ end
51
+
52
+ def update_attributes(attrs = {})
53
+ return if attrs.nil? or attrs.empty?
54
+
55
+ attrs = attrs.with_indifferent_access
56
+
57
+ self.class.keys.each do |key|
58
+ value = attrs[key.name]
59
+
60
+ if value and key.present?(self)
61
+ __send__("#{key.name}=", key.from_hash(value, __send__(key.name)))
62
+ end
63
+ end
64
+
65
+ self
66
+ end
67
+
68
+ def resource_id
69
+ __send__(id_key.name)
70
+ end
71
+
72
+ def self.keys
73
+ @keys ||= []
74
+ end
75
+
76
+ def self.summarized_keys
77
+ @summarized_keys ||= []
78
+ end
79
+
80
+ def self.relations
81
+ @keys.find_all {|k| k.kind_of?(Relation)}
82
+ end
83
+
84
+ def self.resource_name(custom_name = nil)
85
+ @resource_name ||= custom_name or to_s.demodulize.tableize
86
+ end
87
+
88
+ def self.convert_input_keys(converter = nil)
89
+ @convert_input_keys = converter if converter
90
+ @convert_input_keys
91
+ end
92
+
93
+ def self.method_added(method_name)
94
+ return unless not_allowed_names.include?(method_name.to_s)
95
+ puts "warning: redefining '#{method_name}' may cause serious problems"
96
+ end
97
+
98
+ def self.not_allowed_names
99
+ %w(resource_id resource link)
100
+ end
101
+ end
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rest_model/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "rest_model"
7
+ s.version = RestModel::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Victor Rodrigues", "Vinicius Higa", "William Yokoi"]
10
+ s.email = ["victorcrodrigues@gmail.com", "vinicius.higa@locaweb.com.br", "thekina@gmail.com"]
11
+ s.homepage = "http://github.com/rodrigues/rest_model"
12
+ s.summary = %q{}
13
+ s.description = %q{}
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
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"
26
+ end
data/spec/.DS_Store ADDED
Binary file
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe_example "embeds_many/simple" do
6
+ it "parses first embedded item" do
7
+ root.items[0].id.should == 2000
8
+ end
9
+
10
+ it "parses second embedded item" do
11
+ root.items[1].id.should == 2001
12
+ end
13
+ end
14
+
15
+ describe_example "embeds_many/invisible" do
16
+ it "parses invisible items correctly" do
17
+ root.locale.should == "pt-BR"
18
+ root.names.should == {"en"=>"Woot", "pt-BR"=>"Úia", "es"=>"Me gusta"}
19
+ end
20
+
21
+ it "doesn't show embedded items in resource" do
22
+ root.resource.should_not have_key("locale")
23
+ root.resource.should_not have_key("names")
24
+ end
25
+ end
26
+
27
+ describe_example "embeds_many/with_array" do
28
+ it ""
29
+ end
30
+
31
+ describe_example "embeds_many/with_class_name" do
32
+ it "parses embedded item" do
33
+ root.items[0].id.should == 2000
34
+ end
35
+ end
36
+
37
+ describe_example "embeds_many/with_if" do
38
+ context "when an embeddable has a conditional proc (:if)" do
39
+ context "and it evaluates to true" do
40
+ it "parses embedded item" do
41
+ root_with_items.items.first.id.should == "2000"
42
+ end
43
+ end
44
+
45
+ context "and it evaluates to false" do
46
+ it "doesn't parse embedded item" do
47
+ root_without_items.items.should_not be
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ describe_example "embeds_many/with_start_key" do
54
+ it "parses embedded items" do
55
+ root.items.first.id.should == "2000"
56
+ end
57
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe_example "embeds_one/simple" do
4
+ it 'parses embedded item' do
5
+ root.item.id.should == "2000"
6
+ end
7
+ end
8
+
9
+ describe_example "embeds_one/with_class_name" do
10
+ context 'when a different class name is used for embeddable' do
11
+ it 'parses embedded item' do
12
+ root.item.id.should == "2000"
13
+ end
14
+ end
15
+ end
16
+
17
+ describe_example "embeds_one/with_if" do
18
+ context 'when an embeddable has a conditional proc (:if)' do
19
+ context 'and it evaluates to true' do
20
+ it 'parses embedded item' do
21
+ root_with_item.id.should == "1"
22
+ root_with_item.item.id.should == "2000"
23
+ end
24
+ end
25
+
26
+ context 'and it evaluates to false' do
27
+ it "doesn't parse embedded item" do
28
+ root_without_item.id.should == "100"
29
+ root_without_item.item.should_not be
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ describe_example "embeds_one/with_start_key" do
36
+ context 'when there is a start key to parse input' do
37
+ it 'parses embedded item' do
38
+ root.item.id.should == "2000"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe_example "has_many/simple" do
4
+ it 'parses properly' do
5
+ root.id.should == 123
6
+ root.login.should == 'jackiechan2010'
7
+ end
8
+
9
+ describe "#resource" do
10
+ subject {root.resource}
11
+
12
+ it 'has a link' do
13
+ subject[:link].should be_an(Array)
14
+ end
15
+
16
+ [:services, :billing, :devops].each do |rel|
17
+ it "has a #{rel} relation" do
18
+ subject[:link].any? {|l| l[:rel] == rel}.should be_true
19
+ end
20
+
21
+ it "has a href for #{rel} relation" do
22
+ link = subject[:link].find {|l| l[:rel] == rel}
23
+ link[:href].should =~ %r{/customers/123/#{rel}}
24
+ end
25
+ end
26
+ end
27
+ end