collection_json 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
![Spider cow](https://github.com/markburns/collection_json/raw/master/doc/spider-cow.jpg)
|
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
|