collection_json 0.0.1 → 0.0.2
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.
- data/.gitignore +3 -0
- data/.rspec +2 -0
- data/Guardfile +9 -0
- data/README.md +87 -18
- data/collection_json.gemspec +15 -2
- data/doc/hypermedia_client.js.coffee +36 -0
- data/doc/sample.collection.json.js +66 -0
- data/doc/spider-cow.jpg +0 -0
- data/doc/spider-pig.gif +0 -0
- data/lib/collection_json.rb +29 -71
- data/lib/collection_json/collection.rb +34 -0
- data/lib/collection_json/decorator.rb +13 -0
- data/lib/collection_json/exceptions.rb +5 -0
- data/lib/collection_json/{query.rb → gem_version.rb} +1 -2
- data/lib/collection_json/item.rb +60 -0
- data/lib/collection_json/rack.rb +6 -0
- data/lib/collection_json/rack/parser.rb +15 -0
- data/lib/collection_json/template.rb +16 -0
- data/spec/collection_spec.rb +109 -0
- data/spec/decorator_spec.rb +39 -0
- data/spec/integration_spec.rb +28 -0
- data/spec/item_spec.rb +103 -0
- data/spec/rack/parser_spec.rb +23 -0
- data/spec/spec_helper.rb +3 -2
- data/spec/support/sample_mvc.rb +38 -0
- data/spec/template_spec.rb +12 -0
- data/temp_gems_for_ruby_debug_with_1.9.3/linecache19-0.5.13.gem +0 -0
- data/temp_gems_for_ruby_debug_with_1.9.3/ruby-debug-base19-0.11.26.gem +0 -0
- metadata +167 -9
- data/lib/collection_json/crud_operations.rb +0 -4
- data/lib/collection_json/version.rb +0 -3
- data/spec/lib/collection_json_spec.rb +0 -97
data/.gitignore
CHANGED
data/.rspec
ADDED
data/Guardfile
ADDED
data/README.md
CHANGED
@@ -1,9 +1,76 @@
|
|
1
1
|
# CollectionJson
|
2
2
|
|
3
|
-
|
3
|
+
An experimental gem to help with producing Hypermedia APIs with a MIME type of
|
4
4
|
'application/vnd.collection+json'
|
5
5
|
|
6
|
-
see http://amundsen.com/media-types/collection/format
|
6
|
+
see http://amundsen.com/media-types/collection/format/
|
7
|
+
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
The aim is to include the gem in a Rack app to generate hypermedia APIs from
|
12
|
+
your resources, effectively a hypermedia decorator.
|
13
|
+
|
14
|
+
Here's a preview of what you should be able to do in a Rails app:
|
15
|
+
|
16
|
+
|
17
|
+

|
18
|
+
|
19
|
+
```ruby
|
20
|
+
class SpiderCowController < ApplicationController
|
21
|
+
respond_to :collection_json
|
22
|
+
|
23
|
+
def index
|
24
|
+
@spider_cows = SpiderCowDecorator.all do |collection, item|
|
25
|
+
collection.href "http://www.youtube.com/watch?v=FavUpD_IjVY"
|
26
|
+
|
27
|
+
item.links [{href: spider_cow_path(item), rel: "self"},
|
28
|
+
{href: spider_cow_path(item.father), rel: "father"}]
|
29
|
+
end
|
30
|
+
|
31
|
+
respond_with @spider_cows
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class SpiderCow < ActiveRecord::Base
|
36
|
+
#attributes - legs, eyes, udders
|
37
|
+
end
|
38
|
+
|
39
|
+
class SpiderCowDecorator
|
40
|
+
extend CollectionJson::Decorator
|
41
|
+
end
|
42
|
+
```
|
43
|
+
|
44
|
+
Sample output:
|
45
|
+
|
46
|
+
```javascript
|
47
|
+
{"collection" :
|
48
|
+
{
|
49
|
+
"version" :"1.0",
|
50
|
+
"href" :"http://example.org/spider_cows/",
|
51
|
+
|
52
|
+
"links" :[ {"rel" :"father", "href" :"http://example.com/spider_cows/tom"}],
|
53
|
+
|
54
|
+
"items" :
|
55
|
+
[
|
56
|
+
{"data" :
|
57
|
+
[{"name" :"legs", "value" :7},
|
58
|
+
{"name" :"eyes", "value" :8},
|
59
|
+
{"name" :"udders", "value" :"blue"}
|
60
|
+
]
|
61
|
+
},
|
62
|
+
|
63
|
+
{"data" :
|
64
|
+
[{"name" :"legs", "value" :6},
|
65
|
+
{"name" :"udders", "value" :"red"}
|
66
|
+
]
|
67
|
+
}
|
68
|
+
]
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
```
|
73
|
+
|
7
74
|
|
8
75
|
## Installation
|
9
76
|
|
@@ -19,26 +86,25 @@ Or install it yourself as:
|
|
19
86
|
|
20
87
|
$ gem install collection_json
|
21
88
|
|
22
|
-
## Usage
|
23
89
|
|
24
|
-
|
25
|
-
The aim is to be able to include the gem in a Rack app and make for easy
|
26
|
-
generation of hypermedia APIs from your resources, effectively something like a
|
27
|
-
hypermedia presenter.
|
90
|
+
##Notes
|
28
91
|
|
29
|
-
|
30
|
-
Collection+JSON as there is an emphasis on Collections rather than individual
|
31
|
-
items. This makes sense if you think of Rails controllers being plural.
|
92
|
+
Collection+JSON specifies the following concepts
|
32
93
|
|
33
|
-
|
34
|
-
|
94
|
+
Create, Read, Update, Delete, Template and Query
|
95
|
+
which correspond to the ideas in Rails like so:
|
35
96
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
97
|
+
<table>
|
98
|
+
<tr>
|
99
|
+
<th>Verb</th><th>Rails</th><th>Collection+JSON</th>
|
100
|
+
</tr>
|
101
|
+
<tr><td>POST </td><td>create </td><td>create</td></tr>
|
102
|
+
<tr><td>GET </td><td>show </td><td>read</td></tr>
|
103
|
+
<tr><td>PUT </td><td>update </td><td>update</td></tr>
|
104
|
+
<tr><td>DELETE</td><td>destroy </td><td>delete</td></tr>
|
105
|
+
<tr><td>GET </td><td>edit/new</td><td>template</td></tr>
|
106
|
+
<tr><td>GET </td><td>index </td><td>query</td></tr>
|
107
|
+
</table>
|
42
108
|
|
43
109
|
## Contributing
|
44
110
|
|
@@ -47,3 +113,6 @@ being a singular model.
|
|
47
113
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
48
114
|
4. Push to the branch (`git push origin my-new-feature`)
|
49
115
|
5. Create new Pull Request
|
116
|
+
|
117
|
+
|
118
|
+
|
data/collection_json.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
require File.expand_path('../lib/collection_json/
|
2
|
+
require File.expand_path('../lib/collection_json/gem_version', __FILE__)
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Mark Burns"]
|
@@ -7,11 +7,24 @@ Gem::Specification.new do |gem|
|
|
7
7
|
gem.description = %q{Help create Collection+JSON hypermedia APIs}
|
8
8
|
gem.summary = %q{As specified by: http://amundsen.com/media-types/collection/format/#objects}
|
9
9
|
gem.homepage = "https://github.com/markburns/collection_json"
|
10
|
+
gem.add_dependency 'virtus'
|
11
|
+
gem.add_dependency 'activesupport'
|
12
|
+
gem.add_dependency 'i18n'
|
13
|
+
gem.add_dependency 'draper'
|
14
|
+
gem.add_dependency 'funky_accessor'
|
15
|
+
|
16
|
+
gem.add_development_dependency 'guard-rspec'
|
17
|
+
gem.add_development_dependency 'growl'
|
18
|
+
gem.add_development_dependency 'rspec'
|
19
|
+
gem.add_development_dependency 'ruby-debug19'
|
20
|
+
gem.add_development_dependency 'ruby-debug-base19', '0.11.26'
|
21
|
+
gem.add_development_dependency 'linecache19', '0.5.13'
|
22
|
+
gem.add_development_dependency 'awesome_print'
|
10
23
|
|
11
24
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
12
25
|
gem.files = `git ls-files`.split("\n")
|
13
26
|
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
14
27
|
gem.name = "collection_json"
|
15
28
|
gem.require_paths = ["lib"]
|
16
|
-
gem.version = CollectionJson::
|
29
|
+
gem.version = CollectionJson::GEM_VERSION
|
17
30
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
collection = new Collection 'api.spider-cows.com'
|
2
|
+
|
3
|
+
console.log collection.response
|
4
|
+
|
5
|
+
|
6
|
+
{"collection" :
|
7
|
+
{
|
8
|
+
"version" :"1.0",
|
9
|
+
"href" :"http://api.spider-cows.com/",
|
10
|
+
|
11
|
+
"links" :[ {"rel" :"boss_spider", "href" :"http://example.com/spider_cows/tom"}],
|
12
|
+
|
13
|
+
"items" :
|
14
|
+
[
|
15
|
+
{"data" :
|
16
|
+
[{"name" :"legs", "value" :7},
|
17
|
+
{"name" :"eyes", "value" :8},
|
18
|
+
{"name" :"udders", "value" :"blue"}
|
19
|
+
]
|
20
|
+
},
|
21
|
+
|
22
|
+
{"data" :
|
23
|
+
[{"name" :"legs", "value" :6},
|
24
|
+
{"name" :"udders", "value" :"red"}
|
25
|
+
]
|
26
|
+
}
|
27
|
+
]
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
console.log collection.links
|
33
|
+
[{"rel" :"boss_spider", "href" :"http://example.com/spider_cows/tom"}]
|
34
|
+
|
35
|
+
|
36
|
+
console.log collection.links
|
@@ -0,0 +1,66 @@
|
|
1
|
+
{"collection" :
|
2
|
+
{
|
3
|
+
"version" : "1.0",
|
4
|
+
"href" : "http://example.org/friends/",
|
5
|
+
|
6
|
+
"links" : [
|
7
|
+
{"rel" : "feed", "href" : "http://example.org/friends/rss"}
|
8
|
+
],
|
9
|
+
|
10
|
+
"items" : [
|
11
|
+
{
|
12
|
+
"href" : "http://example.org/friends/jdoe",
|
13
|
+
"data" : [
|
14
|
+
{"name" : "full-name", "value" : "J. Doe", "prompt" : "Full Name"},
|
15
|
+
{"name" : "email", "value" : "jdoe@example.org", "prompt" : "Email"}
|
16
|
+
],
|
17
|
+
"links" : [
|
18
|
+
{"rel" : "blog", "href" : "http://examples.org/blogs/jdoe", "prompt" : "Blog"},
|
19
|
+
{"rel" : "avatar", "href" : "http://examples.org/images/jdoe", "prompt" : "Avatar", "render" : "image"}
|
20
|
+
]
|
21
|
+
},
|
22
|
+
|
23
|
+
{
|
24
|
+
"href" : "http://example.org/friends/msmith",
|
25
|
+
"data" : [
|
26
|
+
{"name" : "full-name", "value" : "M. Smith", "prompt" : "Full Name"},
|
27
|
+
{"name" : "email", "value" : "msmith@example.org", "prompt" : "Email"}
|
28
|
+
],
|
29
|
+
"links" : [
|
30
|
+
{"rel" : "blog", "href" : "http://examples.org/blogs/msmith", "prompt" : "Blog"},
|
31
|
+
{"rel" : "avatar", "href" : "http://examples.org/images/msmith", "prompt" : "Avatar", "render" : "image"}
|
32
|
+
]
|
33
|
+
},
|
34
|
+
|
35
|
+
{
|
36
|
+
"href" : "http://example.org/friends/rwilliams",
|
37
|
+
"data" : [
|
38
|
+
{"name" : "full-name", "value" : "R. Williams", "prompt" : "Full Name"},
|
39
|
+
{"name" : "email", "value" : "rwilliams@example.org", "prompt" : "Email"}
|
40
|
+
],
|
41
|
+
"links" : [
|
42
|
+
{"rel" : "blog", "href" : "http://examples.org/blogs/rwilliams", "prompt" : "Blog"},
|
43
|
+
{"rel" : "avatar", "href" : "http://examples.org/images/rwilliams", "prompt" : "Avatar", "render" : "image"}
|
44
|
+
]
|
45
|
+
}
|
46
|
+
],
|
47
|
+
|
48
|
+
"queries" : [
|
49
|
+
{"rel" : "search", "href" : "http://example.org/friends/search", "prompt" : "Search",
|
50
|
+
"data" : [
|
51
|
+
{"name" : "search", "value" : ""}
|
52
|
+
]
|
53
|
+
}
|
54
|
+
],
|
55
|
+
|
56
|
+
"template" : {
|
57
|
+
"data" : [
|
58
|
+
{"name" : "full-name", "value" : "", "prompt" : "Full Name"},
|
59
|
+
{"name" : "email", "value" : "", "prompt" : "Email"},
|
60
|
+
{"name" : "blog", "value" : "", "prompt" : "Blog"},
|
61
|
+
{"name" : "avatar", "value" : "", "prompt" : "Avatar"}
|
62
|
+
|
63
|
+
]
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
data/doc/spider-cow.jpg
ADDED
Binary file
|
data/doc/spider-pig.gif
ADDED
Binary file
|
data/lib/collection_json.rb
CHANGED
@@ -1,84 +1,42 @@
|
|
1
|
+
require "active_support/dependencies/autoload"
|
2
|
+
require "active_support/version"
|
3
|
+
require "delegate"
|
1
4
|
require 'json'
|
5
|
+
require 'virtus'
|
6
|
+
|
7
|
+
require 'active_support/lazy_load_hooks'
|
8
|
+
require 'active_support/concern'
|
2
9
|
require 'active_support/core_ext/string'
|
3
|
-
require '
|
10
|
+
require 'active_support/core_ext/hash'
|
11
|
+
require 'collection_json/gem_version'
|
12
|
+
require 'draper'
|
13
|
+
|
14
|
+
require 'active_support/deprecation'
|
15
|
+
require 'active_support/concern'
|
16
|
+
require 'virtus'
|
17
|
+
require 'virtus/attribute'
|
18
|
+
require 'funky_accessor'
|
4
19
|
|
5
20
|
#see http://amundsen.com/media-types/collection/format/#link-relations
|
6
21
|
|
7
22
|
# 2.1. collection
|
8
23
|
# The collection object contains all the "records" in the representation.
|
9
|
-
# This is a REQUIRED object and there MUST NOT be more than one collection
|
24
|
+
# This is a REQUIRED object and there MUST NOT be more than one collection
|
25
|
+
# object in a Collection+JSON document.
|
10
26
|
# It is a top-level document property.
|
11
27
|
module CollectionJson
|
12
|
-
|
13
|
-
|
14
|
-
def to_json
|
15
|
-
{collection: collection}.to_json
|
16
|
-
end
|
17
|
-
|
18
|
-
def collection
|
19
|
-
{ version: "1.0", #The collection object SHOULD have a version property. For this release,
|
20
|
-
#the value of the version property MUST be set to 1.0.
|
21
|
-
#If there is no version property present, it should be assumed to be set to 1.0.
|
22
|
-
|
23
|
-
href: href, #The collection object SHOULD have an href property.
|
24
|
-
#The href property MUST contain a valid URI.
|
25
|
-
#This URI SHOULD represent the address used to retrieve a representation of the document.
|
26
|
-
#This URI MAY be used to add a new record
|
27
|
-
|
28
|
-
links: links, #The collection object MAY have an links array child property
|
29
|
-
|
30
|
-
items: items, #The collection object MAY have an items array child property.
|
31
|
-
#Each item in a Collection+JSONcollection has an assigned URI (via the href property) and an optional array of one or more data elements along with an optional array of one or more link elements.
|
32
|
-
queries: queries, #The collection object MAY have an queries array child property.
|
33
|
-
|
34
|
-
template: template, #The collection object MAY have an template object child property.
|
35
|
-
error: error #The collection object MAY have an error object child property.
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
|
-
def href
|
40
|
-
@href || "/#{self.class.to_s.underscore.pluralize}"
|
41
|
-
end
|
42
|
-
|
43
|
-
#3.4 links
|
44
|
-
#The links array is an OPTIONAL child property of the items array
|
45
|
-
def links
|
46
|
-
#The Collection+JSON hypermedia type has a limited set of predefined link
|
47
|
-
#relation values and supports additional values applied by implementors
|
48
|
-
#in order to better describe the application domain to which the media
|
49
|
-
#type is applied.
|
50
|
-
@links ||= []
|
51
|
-
end
|
52
|
-
|
53
|
-
def items
|
54
|
-
@items
|
55
|
-
end
|
56
|
-
|
57
|
-
#3.3. queries
|
58
|
-
#The queries array is an OPTIONAL top-level property of the Collection+JSON document.
|
59
|
-
def queries
|
60
|
-
@queries ||= []
|
61
|
-
end
|
28
|
+
extend ActiveSupport::Autoload
|
62
29
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
30
|
+
autoload :Rack
|
31
|
+
autoload :Collection
|
32
|
+
autoload :Link
|
33
|
+
autoload :Item
|
34
|
+
autoload :Query
|
35
|
+
autoload :Template
|
68
36
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
#This is an OPTIONAL object and there MUST NOT be more than one error
|
73
|
-
#object in a Collection+JSON document.
|
74
|
-
#
|
75
|
-
#It is a top-level document property.
|
76
|
-
#
|
77
|
-
#The following elements MAY appear as child properties of the error object:
|
78
|
-
#code message and title.
|
79
|
-
Error = Struct.new :code, :message, :title
|
37
|
+
autoload :InvalidJsonError, 'collection_json/exceptions'
|
38
|
+
autoload :InvalidUriError, 'collection_json/exceptions'
|
39
|
+
autoload :IncompatibleItem, 'collection_json/exceptions'
|
80
40
|
|
81
|
-
|
82
|
-
@error
|
83
|
-
end
|
41
|
+
autoload :Decorator
|
84
42
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module CollectionJson
|
2
|
+
class Collection
|
3
|
+
extend FunkyAccessor
|
4
|
+
funky_accessor :items, :version, :template, :href, :links
|
5
|
+
|
6
|
+
def initialize items
|
7
|
+
@version = "1.0"
|
8
|
+
@items = items.map { |i| Item.new(i) }
|
9
|
+
@template = @items.first.blank_template if @items.any?
|
10
|
+
@links = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def representation
|
14
|
+
collection = {
|
15
|
+
version: version,
|
16
|
+
href: href,
|
17
|
+
links: links,
|
18
|
+
items: item_representations
|
19
|
+
}
|
20
|
+
|
21
|
+
collection.merge!({template: {data: template}}) if template
|
22
|
+
|
23
|
+
{collection: collection}
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_json
|
27
|
+
representation.to_json
|
28
|
+
end
|
29
|
+
|
30
|
+
def item_representations
|
31
|
+
items.map &:singular_representation
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module CollectionJson::Decorator
|
2
|
+
def decorate object
|
3
|
+
klass = object.respond_to?(:each) ? CollectionJson::Collection : CollectionJson::Item
|
4
|
+
|
5
|
+
klass.new(object).tap do |o|
|
6
|
+
if object.respond_to? :each
|
7
|
+
o.items.each { |i| yield o, i } if block_given?
|
8
|
+
else
|
9
|
+
yield o if block_given?
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#The collection object MAY have an items array child property.
|
2
|
+
#Each item in a Collection+JSONcollection has an assigned URI
|
3
|
+
#(via the href property) and an optional array of one or more data
|
4
|
+
#elements along with an optional array of one or more link elements.
|
5
|
+
module CollectionJson
|
6
|
+
class Item < SimpleDelegator
|
7
|
+
extend FunkyAccessor
|
8
|
+
funky_accessor :href, :links, :version, :object
|
9
|
+
|
10
|
+
def initialize object
|
11
|
+
@object = object
|
12
|
+
pre_check
|
13
|
+
super object
|
14
|
+
|
15
|
+
@links = []
|
16
|
+
@version = "1.0"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_json
|
20
|
+
representation.to_json
|
21
|
+
end
|
22
|
+
|
23
|
+
def blank_template
|
24
|
+
template.map{|h| h[:value]=""; h }
|
25
|
+
end
|
26
|
+
|
27
|
+
def template
|
28
|
+
attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
def singular_representation
|
32
|
+
item = {}
|
33
|
+
item.merge!({href: href}) if href
|
34
|
+
item.merge!({data: attributes}) if attributes.any?
|
35
|
+
end
|
36
|
+
|
37
|
+
def representation
|
38
|
+
r = { version: version}
|
39
|
+
|
40
|
+
r.merge!({href: href}) if href
|
41
|
+
r.merge!({links: links}) if links
|
42
|
+
r.merge!({items: [singular_representation]})
|
43
|
+
|
44
|
+
{ collection: r }
|
45
|
+
end
|
46
|
+
|
47
|
+
def attributes
|
48
|
+
@attributes = @object.attributes || {}
|
49
|
+
@attributes.map{|k,v| {name: k.to_s, value: v}}
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def pre_check
|
55
|
+
unless object.respond_to? :attributes
|
56
|
+
raise CollectionJson::IncompatibleItem.new("Decorated items must have an attributes method")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module CollectionJson::Rack
|
2
|
+
class Parser
|
3
|
+
attr_reader :json
|
4
|
+
|
5
|
+
def initialize json_string
|
6
|
+
@json = JSON.parse json_string
|
7
|
+
rescue JSON::ParserError => e
|
8
|
+
raise CollectionJson::InvalidJsonError.new "Couldn't parse: <#{json_string}>, #{e.message}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def valid?
|
12
|
+
false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#The template object contains all the input elements used to add or edit
|
2
|
+
#collection "records." This is an OPTIONAL object and there MUST NOT be more
|
3
|
+
#than one template object in a Collection+JSON document.
|
4
|
+
#It is a top-level document property.
|
5
|
+
#The template object SHOULD have a data array child property.
|
6
|
+
module CollectionJson
|
7
|
+
class Template
|
8
|
+
def initialize *attributes
|
9
|
+
@attributes = attributes
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_json
|
13
|
+
@attributes.map{|a| {name: a, value: ""}}.to_json
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
class SpiderCowDecorator ;extend CollectionJson::Decorator end
|
2
|
+
|
3
|
+
describe CollectionJson::Collection do
|
4
|
+
def cow(id) mock 'spider_cow', link: id, attributes: {name: "cow_#{id}"} end
|
5
|
+
|
6
|
+
let(:items) {[cow(1), cow(2), cow(3)]}
|
7
|
+
|
8
|
+
let(:links) {[{rel: "next", href: "spider_cows/?page=3"}] }
|
9
|
+
|
10
|
+
#crazy archaic plural I'd never heard of, cow -> kine. Thanks ActiveSupport
|
11
|
+
let(:href) { "/spider_kine" }
|
12
|
+
|
13
|
+
let(:spider_cows) do
|
14
|
+
SpiderCowDecorator.decorate items
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#href" do
|
18
|
+
specify do
|
19
|
+
spider_cows.href "/spider_cows"
|
20
|
+
spider_cows.href.should == "/spider_cows"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#links" do
|
25
|
+
specify do
|
26
|
+
spider_cows.links %w(egg banana cheese)
|
27
|
+
spider_cows.links.should == %w(egg banana cheese)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#representation" do
|
32
|
+
specify "has items" do
|
33
|
+
spider_cows.representation[:collection][:items].should ==
|
34
|
+
[{data: [{:name=>"name", :value=>"cow_1"}]},
|
35
|
+
{data: [{:name=>"name", :value=>"cow_2"}]},
|
36
|
+
{data: [{:name=>"name", :value=>"cow_3"}]}]
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "has links" do
|
40
|
+
spider_cows.links links
|
41
|
+
spider_cows.representation[:collection][:links].should == links
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "has href" do
|
45
|
+
spider_cows.href href
|
46
|
+
spider_cows.representation[:collection][:href].should == href
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:banana_fish) do
|
51
|
+
BananaFish.new legs: 7, eyes: 8, color: "blue"
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:banana_fish_2) do
|
55
|
+
BananaFish.new legs: 6, face: "red"
|
56
|
+
end
|
57
|
+
|
58
|
+
describe ".decorate_collection" do
|
59
|
+
let(:expected_2) do
|
60
|
+
{"collection" =>{
|
61
|
+
"version" => "1.0",
|
62
|
+
"href" => "http://example.org/banana_fish/",
|
63
|
+
|
64
|
+
"links" => [
|
65
|
+
{"rel" => "father", "href" => "http://example.com/bananas/tom"},
|
66
|
+
],
|
67
|
+
|
68
|
+
"template" => {"data" =>
|
69
|
+
[{"name"=>"legs", "value"=>""},
|
70
|
+
{"name"=>"eyes", "value"=>""},
|
71
|
+
{"name"=>"color", "value"=>""}]
|
72
|
+
},
|
73
|
+
"items" =>
|
74
|
+
[
|
75
|
+
{"data" =>
|
76
|
+
[{"name" => "legs", "value" => 7},
|
77
|
+
{"name" => "eyes", "value" => 8},
|
78
|
+
{"name" => "color", "value" => "blue"}
|
79
|
+
]
|
80
|
+
},
|
81
|
+
|
82
|
+
{"data" =>
|
83
|
+
[{"name" => "legs", "value" => 6},
|
84
|
+
{"name" => "face", "value" => "red"}
|
85
|
+
]
|
86
|
+
}
|
87
|
+
]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
end
|
91
|
+
let(:collection) do
|
92
|
+
BananaFishDecorator.decorate [banana_fish, banana_fish_2] do |c,i|
|
93
|
+
c.href "http://example.org/banana_fish/"
|
94
|
+
|
95
|
+
c.links [ {"rel" => "father", "href" => "http://example.com/bananas/tom"} ]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
let(:parsed) do
|
100
|
+
JSON[collection.to_json]
|
101
|
+
end
|
102
|
+
|
103
|
+
%w(version href links template).each do |a|
|
104
|
+
specify ", #{a} should match"do
|
105
|
+
parsed["collection"][a].should == expected_2["collection"][a]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
2
|
+
class BananaFish < OpenStruct
|
3
|
+
def attributes
|
4
|
+
@table
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class BananaFishDecorator
|
9
|
+
extend CollectionJson::Decorator
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe CollectionJson::Decorator do
|
14
|
+
context "with a block" do
|
15
|
+
class CatDecorator
|
16
|
+
extend CollectionJson::Decorator
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
cat = {legs: 4, tail: true, id: 1}
|
21
|
+
attributes = cat.merge({attributes: cat})
|
22
|
+
|
23
|
+
cats = [OpenStruct.new(attributes)]
|
24
|
+
|
25
|
+
decorated = CatDecorator.decorate(cats) do |collection, item|
|
26
|
+
collection.links << "/cats"
|
27
|
+
collection.href "/cats"
|
28
|
+
item.links << "/cats/#{item.id}"
|
29
|
+
item.href "/cats/#{item.id}"
|
30
|
+
end
|
31
|
+
|
32
|
+
@decorated = JSON[decorated.to_json]["collection"]
|
33
|
+
end
|
34
|
+
|
35
|
+
specify { @decorated["links"].should == ["/cats"] }
|
36
|
+
specify { @decorated["href"].should == "/cats" }
|
37
|
+
specify { @decorated["items"][0]["href"].should == "/cats/1" }
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require './spec/support/sample_mvc'
|
2
|
+
|
3
|
+
describe "CollectionJson", type: :integration do
|
4
|
+
let(:controller) { SpiderCowController.new }
|
5
|
+
|
6
|
+
describe "controller#index" do
|
7
|
+
before do
|
8
|
+
controller.index
|
9
|
+
@spider_cows = controller.instance_eval{@spider_cows}
|
10
|
+
end
|
11
|
+
|
12
|
+
it "assigns a collection with items" do
|
13
|
+
items = @spider_cows.items
|
14
|
+
items.should be_a Enumerable
|
15
|
+
|
16
|
+
items.each do |x|
|
17
|
+
x.should be_a CollectionJson::Item
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
it "defines the link with a block" do
|
22
|
+
items = @spider_cows.items
|
23
|
+
item = items.first
|
24
|
+
|
25
|
+
item.links.should == [{href: "/spider_cows/1", rel: "self"}]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/item_spec.rb
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
class BananaFish < OpenStruct
|
2
|
+
def attributes
|
3
|
+
@table
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
class BananaFishDecorator
|
8
|
+
extend CollectionJson::Decorator
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
describe CollectionJson::Item do
|
13
|
+
let(:banana_fish) do
|
14
|
+
BananaFish.new legs: 7, eyes: 8, color: "blue"
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:banana_fish_2) do
|
18
|
+
BananaFish.new legs: 6, face: "red"
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".decorate_item" do
|
22
|
+
let(:decorated) do
|
23
|
+
BananaFishDecorator.decorate banana_fish do |b|
|
24
|
+
b.href "http://example.org/banana_fish/1"
|
25
|
+
b.links [{"rel" => "father", "href" => "http://example.com/bananas/tom"},
|
26
|
+
{"rel" => "mother", "href" => "http://example.com/fish/tina"}]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
let(:decorated_2) do
|
32
|
+
BananaFishDecorator.decorate banana_fish_2 do |b|
|
33
|
+
b.href "http://example.org/banana_fish/2"
|
34
|
+
b.links [{"rel" => "father", "href" => "http://example.com/bananas/tom"}]
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
let(:expected) do
|
39
|
+
{"collection" =>
|
40
|
+
{
|
41
|
+
"version" => "1.0",
|
42
|
+
"href" => "http://example.org/banana_fish/1",
|
43
|
+
|
44
|
+
"links" => [
|
45
|
+
{"rel" => "father", "href" => "http://example.com/bananas/tom"},
|
46
|
+
{"rel" => "mother", "href" => "http://example.com/fish/tina"}],
|
47
|
+
|
48
|
+
"items" =>
|
49
|
+
[{
|
50
|
+
"href"=>"http://example.org/banana_fish/1",
|
51
|
+
"data" =>
|
52
|
+
|
53
|
+
[{"name" => "legs", "value" => 7},
|
54
|
+
{"name" => "eyes", "value" => 8},
|
55
|
+
{"name" => "color", "value" => "blue"}
|
56
|
+
]
|
57
|
+
}]}
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
let(:expected_2) do
|
62
|
+
{"collection" =>
|
63
|
+
{
|
64
|
+
"version" => "1.0",
|
65
|
+
"href" => "http://example.org/banana_fish/2",
|
66
|
+
|
67
|
+
"links" => [
|
68
|
+
{"rel" => "father", "href" => "http://example.com/bananas/tom"},
|
69
|
+
],
|
70
|
+
|
71
|
+
"items" =>
|
72
|
+
[
|
73
|
+
{
|
74
|
+
"href"=>"http://example.org/banana_fish/1",
|
75
|
+
"data" =>
|
76
|
+
[{"name" => "legs", "value" => 6},
|
77
|
+
{"name" => "face", "value" => "red"}
|
78
|
+
]
|
79
|
+
}
|
80
|
+
]
|
81
|
+
}}
|
82
|
+
end
|
83
|
+
|
84
|
+
before do
|
85
|
+
decorated_json = decorated.to_json
|
86
|
+
decorated_json_2 = decorated_2.to_json
|
87
|
+
|
88
|
+
@parsed = JSON.parse(decorated_json )
|
89
|
+
@parsed_2 = JSON.parse(decorated_json_2)
|
90
|
+
end
|
91
|
+
|
92
|
+
specify { @parsed.keys.should == expected.keys }
|
93
|
+
specify { @parsed.values.should == expected.values }
|
94
|
+
|
95
|
+
%w(version href link items).each do |a|
|
96
|
+
specify ", #{a} should match" do
|
97
|
+
@parsed[a].should == expected[a]
|
98
|
+
@parsed_2[a].should == expected_2[a]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
describe CollectionJson::Rack::Parser do
|
2
|
+
let(:parser) do
|
3
|
+
CollectionJson::Rack::Parser.new '{"a": 1, "c": "1"}'
|
4
|
+
end
|
5
|
+
|
6
|
+
describe "#initialize" do
|
7
|
+
specify do
|
8
|
+
->{CollectionJson::Rack::Parser.new ""}.should raise_error CollectionJson::InvalidJsonError
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#json" do
|
13
|
+
specify do
|
14
|
+
parser.json.should == {"a" => 1, "c" => "1"}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "#valid?" do
|
19
|
+
specify do
|
20
|
+
parser.should_not be_valid
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -4,10 +4,11 @@
|
|
4
4
|
# loaded once.
|
5
5
|
#
|
6
6
|
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
-
|
7
|
+
require 'collection_json'
|
8
|
+
require 'ruby-debug'
|
8
9
|
|
9
10
|
RSpec.configure do |config|
|
10
11
|
config.treat_symbols_as_metadata_keys_with_true_values = true
|
11
12
|
config.run_all_when_everything_filtered = true
|
12
|
-
config.filter_run :focus
|
13
|
+
#config.filter_run :focus
|
13
14
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class SpiderCowController
|
2
|
+
def index
|
3
|
+
spider_cows = SpiderCow.all
|
4
|
+
|
5
|
+
@spider_cows = SpiderCowDecorator.decorate(spider_cows) do |collection, item|
|
6
|
+
item.links [{href: spider_cow_path(item), rel: "self"}]
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
#in real life this method will be made available
|
11
|
+
#rather than defined here
|
12
|
+
def spider_cow_path cow
|
13
|
+
"/spider_cows/#{cow.id}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SpiderCow
|
18
|
+
attr_accessor :id
|
19
|
+
|
20
|
+
def self.all
|
21
|
+
[SpiderCow.new(1), SpiderCow.new(2), SpiderCow.new(3)]
|
22
|
+
end
|
23
|
+
|
24
|
+
def attributes
|
25
|
+
{id: @id}
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize id
|
29
|
+
@id = id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
class SpiderCowDecorator
|
35
|
+
include CollectionJson::Decorator
|
36
|
+
end
|
37
|
+
|
38
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
2
|
+
|
3
|
+
describe CollectionJson::Template do
|
4
|
+
let(:template) {CollectionJson::Template.new(:legs, :eyes)}
|
5
|
+
|
6
|
+
specify do
|
7
|
+
template.to_json.should == [
|
8
|
+
{name: :legs, value: ""},
|
9
|
+
{name: :eyes, value: ""},
|
10
|
+
].to_json
|
11
|
+
end
|
12
|
+
end
|
Binary file
|
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: collection_json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,140 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
13
|
-
dependencies:
|
12
|
+
date: 2012-03-11 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: virtus
|
16
|
+
requirement: &70360322207560 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70360322207560
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
requirement: &70360322206980 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70360322206980
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: i18n
|
38
|
+
requirement: &70360322206380 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70360322206380
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: draper
|
49
|
+
requirement: &70360322205860 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70360322205860
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: funky_accessor
|
60
|
+
requirement: &70360322205100 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70360322205100
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-rspec
|
71
|
+
requirement: &70360322204500 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70360322204500
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: growl
|
82
|
+
requirement: &70360322203700 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70360322203700
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: rspec
|
93
|
+
requirement: &70360322203080 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>='
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70360322203080
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: ruby-debug19
|
104
|
+
requirement: &70360322202340 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *70360322202340
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: ruby-debug-base19
|
115
|
+
requirement: &70360322201460 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - =
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: 0.11.26
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70360322201460
|
124
|
+
- !ruby/object:Gem::Dependency
|
125
|
+
name: linecache19
|
126
|
+
requirement: &70360322200520 !ruby/object:Gem::Requirement
|
127
|
+
none: false
|
128
|
+
requirements:
|
129
|
+
- - =
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.5.13
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: *70360322200520
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
name: awesome_print
|
137
|
+
requirement: &70360322199440 !ruby/object:Gem::Requirement
|
138
|
+
none: false
|
139
|
+
requirements:
|
140
|
+
- - ! '>='
|
141
|
+
- !ruby/object:Gem::Version
|
142
|
+
version: '0'
|
143
|
+
type: :development
|
144
|
+
prerelease: false
|
145
|
+
version_requirements: *70360322199440
|
14
146
|
description: Help create Collection+JSON hypermedia APIs
|
15
147
|
email:
|
16
148
|
- markthedeveloper@gmail.com
|
@@ -19,17 +151,36 @@ extensions: []
|
|
19
151
|
extra_rdoc_files: []
|
20
152
|
files:
|
21
153
|
- .gitignore
|
154
|
+
- .rspec
|
22
155
|
- Gemfile
|
156
|
+
- Guardfile
|
23
157
|
- LICENSE
|
24
158
|
- README.md
|
25
159
|
- Rakefile
|
26
160
|
- collection_json.gemspec
|
161
|
+
- doc/hypermedia_client.js.coffee
|
162
|
+
- doc/sample.collection.json.js
|
163
|
+
- doc/spider-cow.jpg
|
164
|
+
- doc/spider-pig.gif
|
27
165
|
- lib/collection_json.rb
|
28
|
-
- lib/collection_json/
|
29
|
-
- lib/collection_json/
|
30
|
-
- lib/collection_json/
|
31
|
-
-
|
166
|
+
- lib/collection_json/collection.rb
|
167
|
+
- lib/collection_json/decorator.rb
|
168
|
+
- lib/collection_json/exceptions.rb
|
169
|
+
- lib/collection_json/gem_version.rb
|
170
|
+
- lib/collection_json/item.rb
|
171
|
+
- lib/collection_json/rack.rb
|
172
|
+
- lib/collection_json/rack/parser.rb
|
173
|
+
- lib/collection_json/template.rb
|
174
|
+
- spec/collection_spec.rb
|
175
|
+
- spec/decorator_spec.rb
|
176
|
+
- spec/integration_spec.rb
|
177
|
+
- spec/item_spec.rb
|
178
|
+
- spec/rack/parser_spec.rb
|
32
179
|
- spec/spec_helper.rb
|
180
|
+
- spec/support/sample_mvc.rb
|
181
|
+
- spec/template_spec.rb
|
182
|
+
- temp_gems_for_ruby_debug_with_1.9.3/linecache19-0.5.13.gem
|
183
|
+
- temp_gems_for_ruby_debug_with_1.9.3/ruby-debug-base19-0.11.26.gem
|
33
184
|
homepage: https://github.com/markburns/collection_json
|
34
185
|
licenses: []
|
35
186
|
post_install_message:
|
@@ -50,10 +201,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
201
|
version: '0'
|
51
202
|
requirements: []
|
52
203
|
rubyforge_project:
|
53
|
-
rubygems_version: 1.8.
|
204
|
+
rubygems_version: 1.8.17
|
54
205
|
signing_key:
|
55
206
|
specification_version: 3
|
56
207
|
summary: ! 'As specified by: http://amundsen.com/media-types/collection/format/#objects'
|
57
208
|
test_files:
|
58
|
-
- spec/
|
209
|
+
- spec/collection_spec.rb
|
210
|
+
- spec/decorator_spec.rb
|
211
|
+
- spec/integration_spec.rb
|
212
|
+
- spec/item_spec.rb
|
213
|
+
- spec/rack/parser_spec.rb
|
59
214
|
- spec/spec_helper.rb
|
215
|
+
- spec/support/sample_mvc.rb
|
216
|
+
- spec/template_spec.rb
|
217
|
+
has_rdoc:
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require File.expand_path('spec/spec_helper')
|
2
|
-
|
3
|
-
|
4
|
-
class HerdOfSpiderCows
|
5
|
-
include CollectionJson
|
6
|
-
extend CollectionJson::CrudOperations
|
7
|
-
extend CollectionJson::Query
|
8
|
-
|
9
|
-
def initialize items, links=[], queries=[], template={}
|
10
|
-
@items, @links, @queries, @template = items, links, queries, template
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
#see http://amundsen.com/media-types/collection/format/#link-relations
|
15
|
-
describe CollectionJson do
|
16
|
-
let(:spider_cows) { HerdOfSpiderCows.new [1,2,3],
|
17
|
-
['/spider_cow/1', '/spider_cow/2', 'spider_cow/3'] }
|
18
|
-
|
19
|
-
|
20
|
-
describe "#href" do
|
21
|
-
specify {spider_cows.href.should == "/herd_of_spider_cows" }
|
22
|
-
|
23
|
-
specify do
|
24
|
-
spider_cows.href= "/gathering_of_spider_cows"
|
25
|
-
spider_cows.href.should == "/gathering_of_spider_cows"
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "#links" do
|
30
|
-
specify "has links" do
|
31
|
-
spider_cows.links.should ==
|
32
|
-
['/spider_cow/1', '/spider_cow/2', 'spider_cow/3']
|
33
|
-
end
|
34
|
-
|
35
|
-
specify do
|
36
|
-
spider_cows.links = %w[egg banana cheese]
|
37
|
-
spider_cows.links.should == %w[egg banana cheese]
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe "#collection" do
|
42
|
-
specify do
|
43
|
-
spider_cows.collection.should be_a Hash
|
44
|
-
end
|
45
|
-
|
46
|
-
specify "has items" do
|
47
|
-
spider_cows.collection[:items].should == [1,2,3]
|
48
|
-
end
|
49
|
-
|
50
|
-
specify "has links" do
|
51
|
-
spider_cows.collection[:links].should ==
|
52
|
-
['/spider_cow/1', '/spider_cow/2', 'spider_cow/3']
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
|
58
|
-
describe CollectionJson::CrudOperations do
|
59
|
-
describe ".create" do
|
60
|
-
#1.1.2. Adding an Item
|
61
|
-
#To create a new item in the collection, the client first uses the template object to compose a valid item representation and then uses HTTP POST to send that representation to the server for processing.
|
62
|
-
|
63
|
-
#If the item resource was created successfully, the server responds with a status code of 201 and a Location header that contains the URI of the newly created item resource.
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
describe ".read" do
|
68
|
-
#1.1.3. Reading an Item
|
69
|
-
#Clients can retrieve an existing item resource by sending an HTTP GET request to the URI of an item resource.
|
70
|
-
#If the request is valid, the server will respond with a representation of that item resource.
|
71
|
-
end
|
72
|
-
|
73
|
-
describe ".update" do
|
74
|
-
#1.1.4. Updating an Item
|
75
|
-
#To update an existing resource, the client uses the template object as a guide to composing a replacement item representation and then uses HTTP PUT to send that representation to the server.
|
76
|
-
#If the update is successful, the server will respond with HTTP status code 200 and possibly a representation of the updated item resource representation.
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
describe ".delete" do
|
82
|
-
#1.1.5. Deleting an Item
|
83
|
-
#Clients can delete existing resources by sending an HTTP DELETE request to the URI of the item resource.
|
84
|
-
|
85
|
-
#If the delete request is successful, the server SHOULD respond with an HTTP status code of 204.
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
#1.2. Query Templates
|
92
|
-
#Clients that support the Collection+JSON media type SHOULD be able to recognize and parse query templates found within responses. Query templates consist of a data array associated with an href property. The queries array supports query templates.
|
93
|
-
|
94
|
-
#For query templates, the name/value pairs of the data array set are appended to the URI found in the href property associated with the queries array (with a question-mark ["?"] as separator) and this new URI is sent to the processing agent.
|
95
|
-
describe CollectionJson::Query do
|
96
|
-
|
97
|
-
end
|