rest_model 0.1.0

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