tokamak 1.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +27 -0
  4. data/Gemfile.lock +77 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +69 -0
  7. data/Rakefile +50 -0
  8. data/VERSION +1 -0
  9. data/lib/tokamak.rb +21 -0
  10. data/lib/tokamak/atom.rb +8 -0
  11. data/lib/tokamak/atom/base.rb +87 -0
  12. data/lib/tokamak/atom/builder.rb +107 -0
  13. data/lib/tokamak/atom/helpers.rb +13 -0
  14. data/lib/tokamak/error.rb +6 -0
  15. data/lib/tokamak/json.rb +10 -0
  16. data/lib/tokamak/json/base.rb +83 -0
  17. data/lib/tokamak/json/builder.rb +98 -0
  18. data/lib/tokamak/json/helpers.rb +13 -0
  19. data/lib/tokamak/representation.rb +3 -0
  20. data/lib/tokamak/representation/atom.rb +18 -0
  21. data/lib/tokamak/representation/atom/atom.rng +597 -0
  22. data/lib/tokamak/representation/atom/base.rb +140 -0
  23. data/lib/tokamak/representation/atom/category.rb +39 -0
  24. data/lib/tokamak/representation/atom/entry.rb +56 -0
  25. data/lib/tokamak/representation/atom/factory.rb +48 -0
  26. data/lib/tokamak/representation/atom/feed.rb +108 -0
  27. data/lib/tokamak/representation/atom/link.rb +66 -0
  28. data/lib/tokamak/representation/atom/person.rb +46 -0
  29. data/lib/tokamak/representation/atom/source.rb +57 -0
  30. data/lib/tokamak/representation/atom/tag_collection.rb +36 -0
  31. data/lib/tokamak/representation/atom/xml.rb +94 -0
  32. data/lib/tokamak/representation/generic.rb +20 -0
  33. data/lib/tokamak/representation/json.rb +11 -0
  34. data/lib/tokamak/representation/json/base.rb +25 -0
  35. data/lib/tokamak/representation/json/keys_as_methods.rb +72 -0
  36. data/lib/tokamak/representation/json/link.rb +27 -0
  37. data/lib/tokamak/representation/json/link_collection.rb +21 -0
  38. data/lib/tokamak/representation/links.rb +9 -0
  39. data/lib/tokamak/values.rb +29 -0
  40. data/lib/tokamak/xml.rb +12 -0
  41. data/lib/tokamak/xml/base.rb +60 -0
  42. data/lib/tokamak/xml/builder.rb +115 -0
  43. data/lib/tokamak/xml/helpers.rb +13 -0
  44. data/lib/tokamak/xml/link.rb +31 -0
  45. data/lib/tokamak/xml/links.rb +35 -0
  46. data/spec/integration/atom/atom_spec.rb +191 -0
  47. data/spec/integration/full_atom.xml +92 -0
  48. data/spec/integration/full_json.js +46 -0
  49. data/spec/integration/json/json_spec.rb +172 -0
  50. data/spec/integration/xml/xml_spec.rb +203 -0
  51. data/spec/spec_helper.rb +12 -0
  52. metadata +248 -0
@@ -0,0 +1,92 @@
1
+ <?xml version="1.0" encoding="UTF-8" ?>
2
+ <feed xmlns="http://www.w3.org/2005/Atom">
3
+
4
+ <id>http://example.com/albums/1</id>
5
+ <title>Albums feed</title>
6
+ <subtitle>all your examples are belong to us</subtitle>
7
+ <updated>2010-05-03T16:29:26-03:00</updated>
8
+
9
+ <author>
10
+ <name>John Doe</name>
11
+ <email>joedoe@example.com</email>
12
+ <uri>Http://john.doe.com</uri>
13
+ </author>
14
+
15
+ <author>
16
+ <name>Foo Bar</name>
17
+ <email>foobar@example.com</email>
18
+ </author>
19
+
20
+ <contributor>
21
+ <name>Foo Bar</name>
22
+ <email>foobar@example.com</email>
23
+ </contributor>
24
+
25
+ <generator uri="http://restfulie.com" version="1.0">Restfulie</generator>
26
+ <icon>/icon.jpg</icon>
27
+ <rights>&lt;b&gt;2005 John Doe&lt;/b&gt;</rights>
28
+
29
+ <count xmlns="http://a.special.namespace">2</count>
30
+
31
+ <link href="http://example.com/albums/1" rel="self" />
32
+ <link href="http://example.com/albums/1/csv" rel="alternate" type="text/csv" />
33
+
34
+ <entry>
35
+
36
+ <id>uri:1</id>
37
+ <title>Article 1</title>
38
+ <updated>2010-05-03T16:29:26-03:00</updated>
39
+ <published>2010-05-03T16:29:26-03:00</published>
40
+
41
+ <author>
42
+ <name>Foo Bar</name>
43
+ <email>foobar@example.com</email>
44
+ </author>
45
+
46
+ <summary>Some text.</summary>
47
+
48
+ <category term="sports" scheme="http://a.scheme.com" label="Sports"/>
49
+
50
+ <content>a freaking awesome content</content>
51
+
52
+ <article xmlns="http://article.namespace.com" xmlns:albums="http://example.com/albums">
53
+ <tag>tag1</tag>
54
+ <tag>tag2</tag>
55
+
56
+ <editor name="foozine">
57
+ <category>category 1, category 2</category>
58
+ </editor>
59
+
60
+ <albums:album>
61
+ <albums:id>uri:albums:1</albums:id>
62
+ <albums:title>Album 1</albums:title>
63
+ </albums:album>
64
+
65
+ <albums:album xmlns:song="http://example.com.br">
66
+ <albums:id>1</albums:id>
67
+ <song:title></song:title>
68
+ </albums:album>
69
+ </article>
70
+
71
+ <link href="http://example.com/image/1" rel="image" />
72
+ <link href="http://example.com/image/2" rel="image" type="application/atom+xml" />
73
+
74
+ </entry>
75
+
76
+ <entry>
77
+
78
+ <id>uri:2</id>
79
+ <title>Article 2</title>
80
+ <updated>2010-05-03T16:29:26-03:00</updated>
81
+
82
+ <article xmlns="http://article.namespace.com">
83
+ <tag>tag1</tag>
84
+ <tag>tag2</tag>
85
+ </article>
86
+
87
+ <link href="http://example.com/image/1" rel="image" />
88
+ <link href="http://example.com/image/2" rel="image" type="application/atom+xml" />
89
+
90
+ </entry>
91
+
92
+ </feed>
@@ -0,0 +1,46 @@
1
+ {
2
+ "articles": {
3
+ "link": [
4
+ {
5
+ "rel": "self",
6
+ "href": "http://another.place.com",
7
+ "type": "text/json",
8
+ "charset": "utf-8"
9
+ },
10
+ {
11
+ "rel": "search",
12
+ "href": "http://search.place.com",
13
+ "type": "application/opensearchdescription+xml",
14
+ "charset": "utf-8"
15
+ }
16
+ ],
17
+ "size": 2,
18
+ "freezed": null,
19
+ "article": [
20
+ {
21
+ "link": {
22
+ "rel": "self",
23
+ "href": "http://a.link.com",
24
+ "type": "text/json",
25
+ "profile": "article",
26
+ "charset": "utf-8"
27
+ },
28
+ "title": "a awesome title",
29
+ "subtitle": "Article subtitle",
30
+ "author": "John Maclane"
31
+ },
32
+ {
33
+ "link": {
34
+ "rel": "self",
35
+ "href": "http://a.link.com",
36
+ "type": "text/json",
37
+ "profile": "article",
38
+ "charset": "utf-8"
39
+ },
40
+ "title": "a awesome title",
41
+ "subtitle": "Article subtitle",
42
+ "author": "John Maclane"
43
+ }
44
+ ]
45
+ }
46
+ }
@@ -0,0 +1,172 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require 'json'
3
+
4
+ module Tokamak::Test
5
+ class SimpleClass
6
+ attr_accessor :id, :title, :updated
7
+ def initialize(id,title,updated)
8
+ @id, @title, @updated = id, title, updated
9
+ end
10
+ end
11
+ end
12
+
13
+ describe Tokamak do
14
+ describe 'JSON' do
15
+
16
+ describe "Collection" do
17
+
18
+ it "should create a collection from builder DSL" do
19
+ time = Time.now
20
+ some_articles = [
21
+ {:id => 1, :title => "a great article", :updated => time},
22
+ {:id => 2, :title => "another great article", :updated => time}
23
+ ]
24
+
25
+ json = to_json(some_articles) do |collection|
26
+ collection.values do |values|
27
+ values.id "http://example.com/json"
28
+ values.title "Feed"
29
+ values.updated time
30
+
31
+ values.author {
32
+ values.name "John Doe"
33
+ values.email "joedoe@example.com"
34
+ }
35
+
36
+ values.author {
37
+ values.name "Foo Bar"
38
+ values.email "foobar@example.com"
39
+ }
40
+ end
41
+
42
+ collection.link("next", "http://a.link.com/next")
43
+ collection.link("previous", "http://a.link.com/previous")
44
+
45
+ collection.members(:root => "articles") do |member, article|
46
+ member.values do |values|
47
+ values.id "uri:#{article[:id]}"
48
+ values.title article[:title]
49
+ values.updated article[:updated]
50
+ end
51
+
52
+ member.link("image", "http://example.com/image/1")
53
+ member.link("image", "http://example.com/image/2", :type => "application/json")
54
+ end
55
+ end
56
+
57
+ json = Tokamak::Json.to_hash(json)
58
+ json.id.should == "http://example.com/json"
59
+ json.title.should == "Feed"
60
+ json.author.first.name.should == "John Doe"
61
+ json.author.last.email.should == "foobar@example.com"
62
+
63
+ json.articles.first.id.should == "uri:1"
64
+ json.articles.first.title.should == "a great article"
65
+ end
66
+
67
+ it "should create a collection from a string input" do
68
+ full_json = IO.read(File.dirname(__FILE__) + '/../full_json.js')
69
+ json = to_json(full_json)
70
+
71
+ json["articles"]["size"].should == 2
72
+ json["articles"]["freezed"].should == nil
73
+
74
+ json.articles.__free_method__(:size).size.should == 2
75
+ json.articles.freezed.should == nil end
76
+ end
77
+
78
+ describe "Member" do
79
+
80
+ it "should create a member from builder DSL" do
81
+ time = Time.now
82
+ an_article = {:id => 1, :title => "a great article", :updated => time}
83
+
84
+ entry = to_json(an_article, :atom_type => :entry) do |member, article|
85
+ member.values do |values|
86
+ values.id "uri:#{article[:id]}"
87
+ values.title article[:title]
88
+ values.updated article[:updated]
89
+ end
90
+
91
+ member.link("image", "http://example.com/image/1")
92
+ member.link("image", "http://example.com/image/2", :type => "application/json")
93
+ end
94
+
95
+ entry = Tokamak::Json.to_hash(entry)
96
+ entry["id"].should == "uri:1"
97
+ entry["title"].should == "a great article"
98
+ end
99
+
100
+ it "should be able to declare links inside values block" do
101
+ time = Time.now
102
+ an_article = {:id => 1, :title => "a great article", :updated => time}
103
+
104
+ entry = to_json(an_article, :atom_type => :entry) do |member, article|
105
+ member.values do |values|
106
+ values.id "uri:#{article[:id]}"
107
+ values.title article[:title]
108
+ values.updated article[:updated]
109
+
110
+ values.domain("xmlns" => "http://a.namespace.com") {
111
+ member.link("image", "http://example.com/image/1")
112
+ member.link("image", "http://example.com/image/2", :type => "application/atom+xml")
113
+ }
114
+ end
115
+ end
116
+
117
+ entry = Tokamak::Json.to_hash(entry)
118
+ entry["id"].should == "uri:1"
119
+ entry["title"].should == "a great article"
120
+
121
+ entry["domain"]["link"][0].rel.should == "image"
122
+ end
123
+
124
+ it "should create a member from an already declared recipe" do
125
+
126
+ describe_recipe(:simple_entry) do |member, article|
127
+ member.values do |values|
128
+ values.id "uri:#{article[:id]}"
129
+ values.title article[:title]
130
+ values.updated article[:updated]
131
+ end
132
+
133
+ member.link("image", "http://example.com/image/1")
134
+ member.link("image", "http://example.com/image/2", :type => "application/atom+xml")
135
+ end
136
+
137
+ time = Time.now
138
+ an_article = {:id => 1, :title => "a great article", :updated => time}
139
+
140
+ entry = to_json(an_article, :recipe => :simple_entry)
141
+ entry = Tokamak::Json.to_hash(entry)
142
+
143
+ entry["id"].should == "uri:1"
144
+ entry["title"].should == "a great article"
145
+ end
146
+
147
+ end
148
+
149
+ describe "Errors" do
150
+ it "should raise error for converter without recipe" do
151
+ lambda {
152
+ to_json
153
+ }.should raise_error(Tokamak::ConverterError, "Recipe required")
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+
160
+ def to_json(*args, &recipe)
161
+ Tokamak::Json.to_json(*args, &recipe)
162
+ end
163
+
164
+ def describe_recipe(*args, &recipe)
165
+ Tokamak::Json.describe_recipe(*args, &recipe)
166
+ end
167
+
168
+ def simple_object(*args)
169
+ Tokamak::Test::SimpleClass.new(*args)
170
+ end
171
+
172
+ end
@@ -0,0 +1,203 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ class SimpleClass
4
+ attr_accessor :id, :title, :updated
5
+ def initialize(id,title,updated)
6
+ @id, @title, @updated = id, title, updated
7
+ end
8
+ end
9
+
10
+ class Item
11
+ attr_reader :name
12
+ def initialize(name)
13
+ @name = name
14
+ end
15
+ end
16
+
17
+ describe Tokamak do
18
+ describe 'Xml' do
19
+
20
+ describe "pure to_xml method" do
21
+
22
+ it "should use a default recipe extracting first root element that serializes an entire object if responds to to_xml" do
23
+ time = Time.now
24
+ an_article = {:article => {:id => 1, :title => "a great article", :updated => time}}
25
+
26
+ entry = to_xml(an_article)
27
+ entry.should == an_article[:article].to_xml(:root => "article")
28
+ end
29
+
30
+ it "should use a default recipe that serializes an entire object if responds to to_xml" do
31
+ time = Time.now
32
+ an_article = {:id => 1, :title => "a great article", :updated => time}
33
+
34
+ entry = to_xml(an_article)
35
+ entry.should == an_article.to_xml
36
+ end
37
+
38
+ end
39
+
40
+ describe "entry dsl" do
41
+
42
+ it "should create an entry from builder DSL" do
43
+ an_article = {:article => {:id => 1, :title => "a great article"}}
44
+
45
+ entry = to_xml(an_article) do |member, article|
46
+ member.values do |values|
47
+ values.id "uri:#{article[:article][:id]}"
48
+ values.title article[:article][:title]
49
+ end
50
+
51
+ member.link("image", "http://example.com/image/1")
52
+ member.link("image", "http://example.com/image/2", :type => "application/atom+xml")
53
+ end
54
+
55
+ entry = Hash.from_xml entry
56
+ entry["article"]["id"].should == "uri:1"
57
+ entry["article"]["title"].should == "a great article"
58
+ end
59
+
60
+ it "should be able to declare links inside values block" do
61
+ an_article = {:article => {:id => 1, :title => "a great article"}}
62
+
63
+ entry = to_xml(an_article) do |member, article|
64
+ member.values do |values|
65
+ values.id "uri:#{article[:article][:id]}"
66
+ values.title article[:article][:title]
67
+
68
+ values.domain("xmlns" => "http://a.namespace.com") {
69
+ member.link("image", "http://example.com/image/1")
70
+ member.link("image", "http://example.com/image/2", :type => "application/atom+xml")
71
+ }
72
+ end
73
+
74
+ end
75
+
76
+ entry = Hash.from_xml entry
77
+ entry["article"]["id"].should == "uri:1"
78
+ entry["article"]["title"].should == "a great article"
79
+ entry["article"]["domain"]["link"].size.should == 2
80
+ end
81
+
82
+ it "should be able to method missing to define values" do
83
+ an_article = {:article => {:id => 1, :title => "a great article"}}
84
+
85
+ entry = to_xml(an_article) do |member, article|
86
+ member.id "uri:#{article[:article][:id]}"
87
+ member.title article[:article][:title]
88
+
89
+ member.domain("xmlns" => "http://a.namespace.com") {
90
+ member.link("image", "http://example.com/image/1")
91
+ member.link("image", "http://example.com/image/2", :type => "application/atom+xml")
92
+ }
93
+
94
+ end
95
+
96
+ entry = Hash.from_xml entry
97
+ entry["article"]["id"].should == "uri:1"
98
+ entry["article"]["title"].should == "a great article"
99
+ entry["article"]["domain"]["link"].size.should == 2
100
+ end
101
+
102
+ it "should create an entry from an already declared recipe" do
103
+ describe_recipe(:simple_entry) do |member, article|
104
+ member.values do |values|
105
+ values.id "uri:#{article[:article][:id]}"
106
+ values.title article[:article][:title]
107
+ values.updated article[:article][:updated]
108
+ end
109
+
110
+ member.link("image", "http://example.com/image/1")
111
+ member.link("image", "http://example.com/image/2", :type => "application/atom+xml")
112
+ end
113
+
114
+ time = Time.now
115
+ an_article = {:article => {:id => 1, :title => "a great article", :updated => time}}
116
+
117
+ entry = to_xml(an_article, :atom_type => :entry, :recipe => :simple_entry)
118
+
119
+ entry = Hash.from_xml entry
120
+ entry["article"]["id"].should == "uri:1"
121
+ entry["article"]["title"].should == "a great article"
122
+ end
123
+
124
+ end
125
+
126
+ end
127
+
128
+ def to_xml(*args, &recipe)
129
+ Tokamak::Xml.to_xml(*args, &recipe)
130
+ end
131
+
132
+ def describe_recipe(*args, &recipe)
133
+ Tokamak::Xml.describe_recipe(*args, &recipe)
134
+ end
135
+
136
+ def simple_object(*args)
137
+ SimpleClass.new(*args)
138
+ end
139
+
140
+ end
141
+
142
+ #
143
+ # describe "Feed" do
144
+ # it "should create a feed from builder DSL" do
145
+ # time = Time.now
146
+ # some_articles = {:some_articles => [
147
+ # {:id => 1, :title => "a great article", :updated => time},
148
+ # {:id => 2, :title => "another great article", :updated => time}
149
+ # ]}
150
+ #
151
+ # feed = to_xml(some_articles) do |collection|
152
+ # collection.values do |values|
153
+ # values.id "http://example.com/feed"
154
+ # values.title "Feed"
155
+ # values.updated time
156
+ #
157
+ # values.authors {
158
+ # values.author {
159
+ # values.name "John Doe"
160
+ # values.email "joedoe@example.com"
161
+ # }
162
+ # values.author {
163
+ # values.name "Foo Bar"
164
+ # values.email "foobar@example.com"
165
+ # }
166
+ # }
167
+ # end
168
+ #
169
+ # collection.link("next", "http://a.link.com/next")
170
+ # collection.link("previous", "http://a.link.com/previous")
171
+ #
172
+ # end
173
+ #
174
+ # feed = Hash.from_xml feed
175
+ # feed["some_articles"]["id"].should == "http://example.com/feed"
176
+ # feed["some_articles"]["title"].should == "Feed"
177
+ # # feed["updated"].should == DateTime.parse(time.xmlschema)
178
+ # feed.some_articles.authors.author.first["name"].should == "John Doe"
179
+ # feed.some_articles.authors.author.last["email"].should == "foobar@example.com"
180
+ #
181
+ # end
182
+ #
183
+ # it "should pluralize items on root and singularize on element" do
184
+ # time = Time.now
185
+ # some_articles = [Item.new("training"), Item.new("books")]
186
+ #
187
+ # feed = to_xml(some_articles) do |collection|
188
+ # collection.values do |values|
189
+ # collection.members do |member, item|
190
+ # end
191
+ # end
192
+ # end
193
+ #
194
+ # feed = Hash.from_xml feed
195
+ # feed.keys.first.should =="items"
196
+ # feed.items.keys.first.should =="item"
197
+ # # feed.items.item[0].name.should == "training"
198
+ # # feed.items.item[1].name.should == "books"
199
+ #
200
+ # end
201
+ #
202
+ # end
203
+ #