tokamak 1.0.0.beta2 → 1.0.0.beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/LICENSE +14 -0
  2. data/README.md +159 -0
  3. data/lib/tokamak/builder/base.rb +74 -0
  4. data/lib/tokamak/{json/builder.rb → builder/json.rb} +38 -29
  5. data/lib/tokamak/builder/values.rb +33 -0
  6. data/lib/tokamak/{atom/builder.rb → builder/xml.rb} +46 -41
  7. data/lib/tokamak/builder.rb +22 -0
  8. data/lib/tokamak/errors.rb +3 -0
  9. data/lib/tokamak/hook/rails.rb +78 -0
  10. data/lib/tokamak/hook/sinatra.rb +18 -0
  11. data/lib/tokamak/hook/tilt.rb +42 -0
  12. data/lib/tokamak/hook.rb +6 -0
  13. data/lib/tokamak/recipes.rb +26 -0
  14. data/lib/tokamak/version.rb +13 -0
  15. data/lib/tokamak.rb +14 -18
  16. data/script/console +7 -0
  17. data/test/rails2_skel/Rakefile +16 -0
  18. data/test/rails2_skel/app/controllers/application_controller.rb +1 -0
  19. data/test/rails2_skel/app/controllers/test_controller.rb +18 -0
  20. data/test/rails2_skel/app/views/test/_feed_member.tokamak +9 -0
  21. data/test/rails2_skel/app/views/test/feed.tokamak +24 -0
  22. data/test/rails2_skel/app/views/test/show.tokamak +31 -0
  23. data/test/rails2_skel/config/boot.rb +110 -0
  24. data/test/rails2_skel/config/environment.rb +20 -0
  25. data/test/rails2_skel/config/environments/development.rb +17 -0
  26. data/test/rails2_skel/config/environments/production.rb +28 -0
  27. data/test/rails2_skel/config/environments/test.rb +28 -0
  28. data/test/rails2_skel/config/initializers/cookie_verification_secret.rb +2 -0
  29. data/test/rails2_skel/config/initializers/mime_types.rb +3 -0
  30. data/test/rails2_skel/config/initializers/new_rails_defaults.rb +10 -0
  31. data/test/rails2_skel/config/initializers/session_store.rb +5 -0
  32. data/test/rails2_skel/config/routes.rb +43 -0
  33. data/test/rails2_skel/script/console +3 -0
  34. data/test/test_helper.rb +7 -0
  35. data/test/tokamak/builder/base_test.rb +28 -0
  36. data/test/tokamak/builder/json_test.rb +227 -0
  37. data/test/tokamak/builder/xml_test.rb +254 -0
  38. data/test/tokamak/helper_test.rb +106 -0
  39. data/test/tokamak/hook/rails_test.rb +74 -0
  40. data/test/tokamak/hook/sinatra_test.rb +85 -0
  41. data/test/tokamak/hook/tilt_test.rb +35 -0
  42. data/test/tokamak/recipes_test.rb +90 -0
  43. metadata +106 -113
  44. data/.document +0 -5
  45. data/.rspec +0 -1
  46. data/Gemfile +0 -27
  47. data/Gemfile.lock +0 -77
  48. data/LICENSE.txt +0 -20
  49. data/README.rdoc +0 -69
  50. data/Rakefile +0 -50
  51. data/VERSION +0 -1
  52. data/lib/tokamak/atom/base.rb +0 -87
  53. data/lib/tokamak/atom/helpers.rb +0 -13
  54. data/lib/tokamak/atom.rb +0 -8
  55. data/lib/tokamak/error.rb +0 -6
  56. data/lib/tokamak/json/base.rb +0 -83
  57. data/lib/tokamak/json/helpers.rb +0 -13
  58. data/lib/tokamak/json.rb +0 -10
  59. data/lib/tokamak/representation/atom/atom.rng +0 -597
  60. data/lib/tokamak/representation/atom/base.rb +0 -140
  61. data/lib/tokamak/representation/atom/category.rb +0 -39
  62. data/lib/tokamak/representation/atom/entry.rb +0 -56
  63. data/lib/tokamak/representation/atom/factory.rb +0 -48
  64. data/lib/tokamak/representation/atom/feed.rb +0 -108
  65. data/lib/tokamak/representation/atom/link.rb +0 -66
  66. data/lib/tokamak/representation/atom/person.rb +0 -46
  67. data/lib/tokamak/representation/atom/source.rb +0 -57
  68. data/lib/tokamak/representation/atom/tag_collection.rb +0 -36
  69. data/lib/tokamak/representation/atom/xml.rb +0 -94
  70. data/lib/tokamak/representation/atom.rb +0 -18
  71. data/lib/tokamak/representation/generic.rb +0 -20
  72. data/lib/tokamak/representation/json/base.rb +0 -25
  73. data/lib/tokamak/representation/json/keys_as_methods.rb +0 -72
  74. data/lib/tokamak/representation/json/link.rb +0 -27
  75. data/lib/tokamak/representation/json/link_collection.rb +0 -21
  76. data/lib/tokamak/representation/json.rb +0 -11
  77. data/lib/tokamak/representation/links.rb +0 -9
  78. data/lib/tokamak/representation.rb +0 -3
  79. data/lib/tokamak/values.rb +0 -29
  80. data/lib/tokamak/xml/base.rb +0 -60
  81. data/lib/tokamak/xml/builder.rb +0 -115
  82. data/lib/tokamak/xml/helpers.rb +0 -13
  83. data/lib/tokamak/xml/link.rb +0 -31
  84. data/lib/tokamak/xml/links.rb +0 -35
  85. data/lib/tokamak/xml.rb +0 -12
  86. data/spec/integration/atom/atom_spec.rb +0 -191
  87. data/spec/integration/full_atom.xml +0 -92
  88. data/spec/integration/full_json.js +0 -46
  89. data/spec/integration/json/json_spec.rb +0 -172
  90. data/spec/integration/xml/xml_spec.rb +0 -203
  91. data/spec/spec_helper.rb +0 -12
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ Copyright (c) 2010 Abril Midia
2
+ All rights reserved.
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # Tokamak
2
+
3
+ Is a template engine for hypermedia resources that provides a single DSL to generate several media types representations.
4
+
5
+ This version supports json and xml generation (you can add other media types
6
+ easily)
7
+
8
+ The lib provide hooks for:
9
+
10
+ * Rails
11
+ * Sinatra
12
+ * Tilt ([https://github.com/rtomayko/tilt](https://github.com/rtomayko/tilt))
13
+
14
+ Just put `require "tokamak/hook/[sinatra|rails|tilt]"` on your app. See unit
15
+ tests for hook samples.
16
+
17
+ You are also able to implement hooks for other frameworks.
18
+
19
+ ## Sample
20
+
21
+ ### Tokamak code
22
+
23
+ collection(@some_articles) do |collection|
24
+ collection.values do |values|
25
+ values.id "http://example.com/json"
26
+ values.title "Feed"
27
+ values.updated Time.now
28
+
29
+ values.author {
30
+ values.name "John Doe"
31
+ values.email "joedoe@example.com"
32
+ }
33
+
34
+ values.author {
35
+ values.name "Foo Bar"
36
+ values.email "foobar@example.com"
37
+ }
38
+ end
39
+
40
+ collection.link("next" , "http://a.link.com/next")
41
+ collection.link("previous", "http://a.link.com/previous")
42
+
43
+ collection.members(:root => "articles") do |member, article|
44
+ member.values do |values|
45
+ values.id "uri:#{article[:id]}"
46
+ values.title article[:title]
47
+ values.updated article[:updated]
48
+ end
49
+
50
+ member.link("image", "http://example.com/image/1")
51
+ member.link("image", "http://example.com/image/2", :type => "application/json")
52
+ end
53
+ end
54
+
55
+ Generates the following representations:
56
+
57
+ ### JSON
58
+
59
+ {
60
+ "author": [{
61
+ "name": "John Doe",
62
+ "email": "joedoe@example.com"
63
+ },
64
+ {
65
+ "name": "Foo Bar",
66
+ "email": "foobar@example.com"
67
+ }],
68
+ "title": "Feed",
69
+ "id": "http://example.com/json",
70
+ "link": [{
71
+ "href": "http://a.link.com/next",
72
+ "rel": "next",
73
+ "type": "application/json"
74
+ },
75
+ {
76
+ "href": "http://a.link.com/previous",
77
+ "rel": "previous",
78
+ "type": "application/json"
79
+ }],
80
+ "articles": [{
81
+ "title": "a great article",
82
+ "id": "uri:1",
83
+ "link": [{
84
+ "href": "http://example.com/image/1",
85
+ "rel": "image",
86
+ "type": "application/json"
87
+ },
88
+ {
89
+ "type": "application/json",
90
+ "href": "http://example.com/image/2",
91
+ "rel": "image",
92
+ "type": "application/json"
93
+ }],
94
+ "updated": "2011-01-05T10:40:58-02:00"
95
+ },
96
+ {
97
+ "title": "another great article",
98
+ "id": "uri:2",
99
+ "link": [{
100
+ "href": "http://example.com/image/1",
101
+ "rel": "image",
102
+ "type": "application/json"
103
+ },
104
+ {
105
+ "type": "application/json",
106
+ "href": "http://example.com/image/2",
107
+ "rel": "image",
108
+ "type": "application/json"
109
+ }],
110
+ "updated": "2011-01-05T10:40:58-02:00"
111
+ }],
112
+ "updated": "2011-01-05T10:40:58-02:00"
113
+ }
114
+
115
+ ### XML
116
+
117
+ <?xml version="1.0"?>
118
+ <root>
119
+ <id>http://example.com/json</id>
120
+ <title>Feed</title>
121
+ <updated>2011-01-05T10:40:58-02:00</updated>
122
+ <author>
123
+ <name>John Doe</name>
124
+ <email>joedoe@example.com</email>
125
+ </author>
126
+ <author>
127
+ <name>Foo Bar</name>
128
+ <email>foobar@example.com</email>
129
+ </author>
130
+ <link href="http://a.link.com/next" rel="next" type="application/xml"/>
131
+ <link href="http://a.link.com/previous" rel="previous" type="application/xml"/>
132
+ <articles>
133
+ <id>uri:1</id>
134
+ <title>a great article</title>
135
+ <updated>2011-01-05T10:40:58-02:00</updated>
136
+ <link href="http://example.com/image/1" rel="image" type="application/xml"/>
137
+ <link href="http://example.com/image/2" type="application/json" rel="image"/>
138
+ </articles>
139
+ <articles>
140
+ <id>uri:2</id>
141
+ <title>another great article</title>
142
+ <updated>2011-01-05T10:40:58-02:00</updated>
143
+ <link href="http://example.com/image/1" rel="image" type="application/xml"/>
144
+ <link href="http://example.com/image/2" type="application/json" rel="image"/>
145
+ </articles>
146
+ </root>
147
+
148
+ ## Other features
149
+
150
+ * You can declare recipes once and reuse it later (see `Tokamak::Recipes`)
151
+ * You can extend `Tokamak::Builder::Base` to support a custom media type.
152
+ * You can customize the DSL entrypoint helpers, used by the hooks (see `Tokamak::Builder::HelperTest`)
153
+
154
+ ## Want to know more?
155
+
156
+ Please check the unit tests, you can see a lot of richer samples, including tests for the hooks.
157
+
158
+ *This library was extracted from [Restfulie](https://github.com/caelum/restfulie) and then heavy refactored. The same terms apply, see LICENSE.txt*
159
+
@@ -0,0 +1,74 @@
1
+ module Tokamak
2
+ module Builder
3
+ class Base
4
+
5
+ @@global_media_types = {}
6
+
7
+ class << self
8
+ def builder_for(*args)
9
+ # class instance variable to store media types handled by a builder
10
+ @media_types = args
11
+ args.each do |media_type|
12
+ @@global_media_types[media_type] = self
13
+ end
14
+ end
15
+
16
+ def media_types
17
+ @media_types
18
+ end
19
+
20
+ def global_media_types
21
+ @@global_media_types
22
+ end
23
+
24
+ def build(obj, options = {}, &block)
25
+ if block_given?
26
+ recipe = block
27
+ else
28
+ recipe = options.delete(:recipe)
29
+ end
30
+
31
+ unless recipe.respond_to?(:call)
32
+ recipe = Tokamak::Recipes[recipe]
33
+ raise Tokamak::BuilderError.new("Recipe required to build representation.") unless recipe.respond_to?(:call)
34
+ end
35
+
36
+ builder = self.new(obj, options)
37
+
38
+ recipe.call(*[builder, obj, options][0, recipe.arity])
39
+
40
+ builder.representation
41
+ end
42
+
43
+ def helper
44
+ unless instance_variable_get(:@helper_module)
45
+ @helper_module = Tokamak::Builder.helper_module_for(self)
46
+ end
47
+ @helper_module
48
+ end
49
+
50
+ def collection_helper_default_options(options = {}, &block)
51
+ generic_helper(:collection, options, &block)
52
+ end
53
+
54
+ def member_helper_default_options(type, options = {}, &block)
55
+ generic_helper(:member, options, &block)
56
+ end
57
+
58
+ def generic_helper(section, options = {}, &block)
59
+ helper.send(:remove_method, section)
60
+ var_name = "@@more_options_#{section.to_s}".to_sym
61
+ helper.send(:class_variable_set, var_name, options)
62
+ helper.module_eval <<-EOS
63
+ def #{section.to_s}(obj, *args, &block)
64
+ #{var_name}.merge!(args.shift)
65
+ args.unshift(#{var_name})
66
+ #{self.name}.build(obj, *args, &block)
67
+ end
68
+ EOS
69
+ end
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -1,67 +1,75 @@
1
+ require "json/pure"
2
+
1
3
  module Tokamak
2
- module Json
3
- class Builder
4
- def initialize(obj, initial_obj = {})
5
- @doc = initial_obj
4
+ module Builder
5
+ class Json < Tokamak::Builder::Base
6
+
7
+ builder_for "application/json"
8
+
9
+ attr_reader :raw
10
+
11
+ def initialize(obj, options = {})
12
+ @raw = options[:root] ? { options[:root] => {} } : {}
13
+ @current = options[:root] ? @raw[options[:root]] : @raw
6
14
  @obj = obj
7
- @current = @doc
8
15
  end
9
-
10
- def values(options = nil, &block)
11
- yield Values.new(self)
12
- end
13
-
16
+
14
17
  def members(options = {}, &block)
15
- collection = options[:collection] || @obj
16
- raise Error::BuilderError.new("Members method require a collection to execute") unless collection.respond_to?(:each)
17
- root = options[:root] || Tokamak.root_element_for(collection)
18
-
18
+ collection = options[:collection] || @obj
19
+ raise Tokamak::BuilderError.new("Members method require a collection to execute") unless collection.respond_to?(:each)
20
+ root = options[:root] || "members"
21
+
22
+ add_to_current(root, [])
19
23
  collection.each do |member|
20
24
  node = {}
21
-
25
+
22
26
  parent = @current
23
27
  @current = node
24
28
  block.call(self, member)
25
29
  @current = parent
26
-
30
+
27
31
  add_to_current(root, node)
28
32
  end
29
33
  end
30
-
34
+
35
+ def values(options = {}, &block)
36
+ yield Values.new(self)
37
+ end
38
+
31
39
  def link(relationship, uri, options = {})
32
40
  options["rel"] = relationship.to_s
33
41
  options["href"] = uri
34
- options["type"] ||= "application/json"
42
+ options["type"] ||= options[:type] || "application/json"
35
43
  insert_value("link", nil, options)
36
44
  end
37
-
45
+
38
46
  def insert_value(name, prefix, *args, &block)
39
47
  node = create_element(block_given?, *args)
40
-
48
+
41
49
  if block_given?
42
50
  parent = @current
43
51
  @current = node
44
52
  block.call
45
53
  @current = parent
46
54
  end
47
-
55
+
48
56
  add_to_current(name, node)
49
57
  end
50
-
58
+
51
59
  def representation
52
- Tokamak::Representation::Json.create(@doc).to_json
60
+ @raw.to_json
53
61
  end
54
-
62
+
55
63
  private
56
-
64
+
57
65
  def create_element(has_block, *args)
58
66
  vals = []
59
67
  hashes = []
60
-
68
+
61
69
  args.each do |arg|
62
70
  arg.kind_of?(Hash) ? hashes << arg : vals << arg
63
71
  end
64
-
72
+
65
73
  if hashes.empty?
66
74
  # only simple values
67
75
  unless vals.empty?
@@ -72,7 +80,7 @@ module Tokamak
72
80
  end
73
81
  else
74
82
  # yes we have hashes
75
- node = {}
83
+ node = {}
76
84
  hashes.each { |hash| node.merge!(hash) }
77
85
  unless vals.empty?
78
86
  vals = vals.first if vals.size == 1
@@ -81,7 +89,7 @@ module Tokamak
81
89
  node
82
90
  end
83
91
  end
84
-
92
+
85
93
  def add_to_current(name, value)
86
94
  if @current[name]
87
95
  if @current[name].kind_of?(Array)
@@ -93,6 +101,7 @@ module Tokamak
93
101
  @current[name] = value
94
102
  end
95
103
  end
104
+
96
105
  end
97
106
  end
98
107
  end
@@ -0,0 +1,33 @@
1
+ module Tokamak
2
+ module Builder
3
+
4
+ # This is a Blank Slate class to support the renderization of the values block of Builder DSLs
5
+ # Every Media type should implement a Builder with a insert_value method that renders the values block to a specific format
6
+ class Values
7
+ attr_accessor :builder
8
+
9
+ # BlankSlate
10
+ instance_methods.each do |m|
11
+ undef_method m unless m.to_s =~ /\[\]|method_missing|respond_to\?|^__/
12
+ end
13
+
14
+ def initialize(builder)
15
+ @builder = builder
16
+ @current_prefix = nil
17
+ end
18
+
19
+ def [](prefix)
20
+ @current_prefix = prefix
21
+ self
22
+ end
23
+
24
+ def method_missing(symbol, *args, &block)
25
+ name = symbol.to_s
26
+ prefix = @current_prefix
27
+ @current_prefix = nil
28
+ @builder.insert_value(name, prefix, *args, &block)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -1,15 +1,32 @@
1
+ require "nokogiri"
2
+
1
3
  module Tokamak
2
- module Atom
3
- class Builder
4
- attr_accessor :atom_type
5
- def initialize(atom_type, obj)
6
- @doc = Nokogiri::XML::Document.new
7
- @obj = obj
8
- @parent = @doc.create_element(atom_type.to_s)
9
- @parent.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
10
- @parent.parent = @doc
4
+ module Builder
5
+ class Xml < Tokamak::Builder::Base
6
+
7
+ builder_for "application/xml", "text/xml"
8
+
9
+ attr_reader :raw
10
+
11
+ def initialize(obj, options = {})
12
+ @raw = Nokogiri::XML::Document.new
13
+ @obj = obj
14
+ @parent = @raw.create_element(options[:root] || "root")
15
+ @parent.parent = @raw
11
16
  end
12
-
17
+
18
+ def members(options = {}, &block)
19
+ collection = options[:collection] || @obj
20
+ raise Tokamak::BuilderError.new("Members method require a collection to execute") unless collection.respond_to?(:each)
21
+ collection.each do |member|
22
+ member_root = @raw.create_element(options[:root] || "member")
23
+ member_root.parent = @parent
24
+ @parent = member_root
25
+ block.call(self, member)
26
+ @parent = member_root.parent
27
+ end
28
+ end
29
+
13
30
  def values(options = {}, &block)
14
31
  options.each do |key,value|
15
32
  attr = key.to_s
@@ -17,47 +34,35 @@ module Tokamak
17
34
  ns = attr.split(":", 2)[1]
18
35
  @parent.add_namespace_definition(ns, value)
19
36
  end
20
- end
21
- yield Values.new(self)
22
- end
23
-
24
- def members(options = {}, &block)
25
- collection = options[:collection] || @obj
26
- raise Error::BuilderError.new("Members method require a collection to execute") unless collection.respond_to?(:each)
27
- collection.each do |member|
28
- entry = @doc.create_element("entry")
29
- entry.parent = @parent
30
- @parent = entry
31
- block.call(self, member)
32
- @parent = entry.parent
33
37
  end
38
+ yield Values.new(self)
34
39
  end
35
-
40
+
36
41
  def link(relationship, uri, options = {})
37
42
  options["rel"] = relationship.to_s
38
43
  options["href"] = uri
39
- options["type"] ||= "application/atom+xml"
44
+ options["type"] ||= options[:type] || "application/xml"
40
45
  insert_value("link", nil, options)
41
46
  end
42
-
47
+
43
48
  def insert_value(name, prefix, *args, &block)
44
49
  node = create_element(name.to_s, prefix, *args)
45
- node.parent = @parent
50
+ node.parent = @parent
46
51
  if block_given?
47
52
  @parent = node
48
53
  block.call
49
54
  @parent = node.parent
50
55
  end
51
56
  end
52
-
57
+
53
58
  def representation
54
- Tokamak::Representation::Atom::Factory.create(@doc)
59
+ @raw.to_xml
55
60
  end
56
-
61
+
57
62
  private
58
-
63
+
59
64
  def create_element(node, prefix, *args)
60
- node = @doc.create_element(node) do |n|
65
+ node = @raw.create_element(node) do |n|
61
66
  if prefix
62
67
  if namespace = prefix_valid?(prefix)
63
68
  # Adding namespace prefix
@@ -65,7 +70,7 @@ module Tokamak
65
70
  namespace = nil
66
71
  end
67
72
  end
68
-
73
+
69
74
  args.each do |arg|
70
75
  case arg
71
76
  # Adding XML attributes
@@ -80,28 +85,28 @@ module Tokamak
80
85
  n[k.to_s] = v.to_s
81
86
  }
82
87
  # Adding XML node content
83
- else
84
- arg.kind_of?(Time) || arg.kind_of?(DateTime) ? content = arg.xmlschema : content = arg
88
+ else
89
+ content = arg.kind_of?(Time) || arg.kind_of?(DateTime) ? arg.xmlschema : arg
85
90
  n.content = content
86
91
  end
87
92
  end
88
93
  end
89
94
  end
90
-
95
+
91
96
  def prefix_valid?(prefix)
92
97
  ns = @parent.namespace_definitions.find { |x| x.prefix == prefix.to_s }
93
-
98
+
94
99
  unless ns
95
100
  @parent.ancestors.each do |a|
96
- next if a == @doc
101
+ next if a == @raw
97
102
  ns = a.namespace_definitions.find { |x| x.prefix == prefix.to_s }
98
103
  break if ns
99
- end
104
+ end
100
105
  end
101
-
106
+
102
107
  return ns
103
- #TODO: raise ArgumentError, "Namespace #{prefix} has not been defined" if wanted
104
108
  end
109
+
105
110
  end
106
111
  end
107
112
  end
@@ -0,0 +1,22 @@
1
+ module Tokamak
2
+ module Builder
3
+ autoload :Base , "tokamak/builder/base"
4
+ autoload :Values, "tokamak/builder/values"
5
+ autoload :Json , "tokamak/builder/json"
6
+ autoload :Xml , "tokamak/builder/xml"
7
+
8
+ def self.helper_module_for(const)
9
+ mod = Module.new
10
+ mod.module_eval <<-EOS
11
+ def collection(obj, *args, &block)
12
+ #{const.name}.build(obj, *args, &block)
13
+ end
14
+
15
+ def member(obj, *args, &block)
16
+ #{const.name}.build(obj, *args, &block)
17
+ end
18
+ EOS
19
+ mod
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Tokamak
2
+ class BuilderError < StandardError; end
3
+ end
@@ -0,0 +1,78 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../tokamak.rb') unless defined? ::Tokamak
2
+
3
+ module Tokamak
4
+ module Hook
5
+ module Rails
6
+
7
+ class Tokamak < ::ActionView::TemplateHandler
8
+ include ::ActionView::TemplateHandlers::Compilable
9
+
10
+ def compile(template)
11
+ "@content_type_helpers = ::Tokamak.builder_lookup(self.response.content_type).helper; " +
12
+ "extend @content_type_helpers; " +
13
+ "extend Tokamak::Hook::Rails::Helpers; " +
14
+ "code_block = lambda { #{template.source} };" +
15
+ "builder = code_block.call; " +
16
+ "builder"
17
+ end
18
+ end
19
+
20
+ module Helpers
21
+ # Load a partial template to execute in describe
22
+ #
23
+ # For example:
24
+ #
25
+ # Passing the current context to partial in template:
26
+ #
27
+ # member(@album) do |member, album|
28
+ # partial('member', binding)
29
+ # end
30
+ #
31
+ # in partial:
32
+ #
33
+ # member.links << link(:rel => :artists, :href => album_artists_url(album))
34
+ #
35
+ # Or passing local variables assing
36
+ #
37
+ # collection(@albums) do |collection|
38
+ # collection.members do |member, album|
39
+ # partial("member", :locals => {:member => member, :album => album})
40
+ # end
41
+ # end
42
+ #
43
+ def partial(partial_path, caller_binding = nil)
44
+ template = _pick_partial_template(partial_path)
45
+
46
+ # Create a context to assing variables
47
+ if caller_binding.kind_of?(Hash)
48
+ Proc.new do
49
+ extend @content_type_helpers
50
+ context = eval("(class << self; self; end)", binding)
51
+
52
+ unless caller_binding[:locals].nil?
53
+ caller_binding[:locals].each do |k, v|
54
+ context.send(:define_method, k.to_sym) { v }
55
+ end
56
+ end
57
+
58
+ partial(partial_path, binding)
59
+ end.call
60
+ else
61
+ eval(template.source, caller_binding, template.path)
62
+ end
63
+ end
64
+ end
65
+
66
+ if defined? ::ActionView::Template and ::ActionView::Template.respond_to?(:register_template_handler)
67
+ ::ActionView::Template
68
+ else
69
+ ::ActionView::Base
70
+ end.register_template_handler(:tokamak, Tokamak)
71
+
72
+ if defined? ::ActionController::Base
73
+ ::ActionController::Base.exempt_from_layout :tokamak
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../tokamak.rb') unless defined? ::Tokamak
2
+ require "tokamak/hook/tilt"
3
+
4
+ module Tokamak
5
+ module Hook
6
+ module Sinatra
7
+
8
+ module ::Sinatra::Templates
9
+
10
+ def tokamak(template, options={}, locals={})
11
+ options.merge! :layout => false, :media_type => response["Content-Type"]
12
+ render :tokamak, template, options, locals
13
+ end
14
+
15
+ end
16
+ end
17
+ end
18
+ end