hypertemplate 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +29 -0
- data/README.md +134 -0
- data/lib/hypertemplate.rb +14 -0
- data/lib/hypertemplate/builder.rb +33 -0
- data/lib/hypertemplate/builder/base.rb +111 -0
- data/lib/hypertemplate/builder/json.rb +132 -0
- data/lib/hypertemplate/builder/values.rb +33 -0
- data/lib/hypertemplate/builder/xml.rb +119 -0
- data/lib/hypertemplate/errors.rb +3 -0
- data/lib/hypertemplate/hook.rb +6 -0
- data/lib/hypertemplate/hook/rails.rb +112 -0
- data/lib/hypertemplate/hook/sinatra.rb +44 -0
- data/lib/hypertemplate/hook/tilt.rb +68 -0
- data/lib/hypertemplate/recipes.rb +25 -0
- data/lib/hypertemplate/registry.rb +24 -0
- data/lib/hypertemplate/version.rb +13 -0
- data/script/console +7 -0
- data/test/hypertemplate/builder/base_test.rb +45 -0
- data/test/hypertemplate/builder/json_test.rb +506 -0
- data/test/hypertemplate/builder/values_test.rb +12 -0
- data/test/hypertemplate/builder/xml_test.rb +479 -0
- data/test/hypertemplate/helper_test.rb +116 -0
- data/test/hypertemplate/hook/rails_test.rb +77 -0
- data/test/hypertemplate/hook/sinatra_test.rb +89 -0
- data/test/hypertemplate/hook/tilt_test.rb +48 -0
- data/test/hypertemplate/recipes_test.rb +94 -0
- data/test/rails2_skel/Rakefile +16 -0
- data/test/rails2_skel/app/controllers/application_controller.rb +1 -0
- data/test/rails2_skel/app/controllers/test_controller.rb +18 -0
- data/test/rails2_skel/app/views/test/_feed_member.tokamak +9 -0
- data/test/rails2_skel/app/views/test/feed.tokamak +24 -0
- data/test/rails2_skel/app/views/test/show.hyper +31 -0
- data/test/rails2_skel/config/boot.rb +110 -0
- data/test/rails2_skel/config/environment.rb +20 -0
- data/test/rails2_skel/config/environments/development.rb +17 -0
- data/test/rails2_skel/config/environments/production.rb +28 -0
- data/test/rails2_skel/config/environments/test.rb +28 -0
- data/test/rails2_skel/config/initializers/cookie_verification_secret.rb +2 -0
- data/test/rails2_skel/config/initializers/mime_types.rb +3 -0
- data/test/rails2_skel/config/initializers/new_rails_defaults.rb +10 -0
- data/test/rails2_skel/config/initializers/session_store.rb +5 -0
- data/test/rails2_skel/config/routes.rb +43 -0
- data/test/rails2_skel/log/development.log +10190 -0
- data/test/rails2_skel/script/console +3 -0
- data/test/test_helper.rb +9 -0
- metadata +207 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
module Hypertemplate
|
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|object_id|send|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
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Hypertemplate
|
2
|
+
module Builder
|
3
|
+
class Xml < Hypertemplate::Builder::Base
|
4
|
+
|
5
|
+
def self.media_types
|
6
|
+
["application/xml", "text/xml"]
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_reader :raw
|
10
|
+
|
11
|
+
def initialize(obj, options = {})
|
12
|
+
initialize_library
|
13
|
+
@raw = Nokogiri::XML::Document.new
|
14
|
+
@obj = obj
|
15
|
+
@parent = @raw.create_element(options[:root] || "root")
|
16
|
+
@parent.parent = @raw
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize_library
|
20
|
+
return if defined?(::Nokogiri)
|
21
|
+
require "nokogiri"
|
22
|
+
end
|
23
|
+
|
24
|
+
def members(options = {}, &block)
|
25
|
+
collection = options[:collection] || @obj
|
26
|
+
raise Hypertemplate::BuilderError.new("Members method require a collection to execute") unless collection.respond_to?(:each)
|
27
|
+
name = options[:root] || "member"
|
28
|
+
collection.each do |element|
|
29
|
+
member_root = @raw.create_element(name)
|
30
|
+
member_root.parent = @parent
|
31
|
+
@parent = member_root
|
32
|
+
if block.arity==1
|
33
|
+
# new dsl
|
34
|
+
block.call(element)
|
35
|
+
else
|
36
|
+
# old dsl (deprecate at 1.3?)
|
37
|
+
block.call(self, element)
|
38
|
+
end
|
39
|
+
@parent = member_root.parent
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def values(options = {}, &block)
|
44
|
+
options.each do |key,value|
|
45
|
+
apply_namespace(@parent, key.to_s, value)
|
46
|
+
end
|
47
|
+
yield Values.new(self)
|
48
|
+
end
|
49
|
+
|
50
|
+
def link(relationship, uri, options = {})
|
51
|
+
options["rel"] = relationship.to_s
|
52
|
+
options["href"] = uri
|
53
|
+
options["type"] ||= options[:type] || "application/xml"
|
54
|
+
insert_value("link", nil, options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def insert_value(name, prefix, *args, &block)
|
58
|
+
# Protected if empty array
|
59
|
+
unless args.size == 1 and args.first == []
|
60
|
+
node = create_element(name.to_s, prefix, *args)
|
61
|
+
node.parent = @parent
|
62
|
+
if block_given?
|
63
|
+
@parent = node
|
64
|
+
block.call
|
65
|
+
@parent = node.parent
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def representation
|
71
|
+
@raw.to_xml
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
def apply_namespace(node, key, value)
|
77
|
+
if key =~ /^xmlns(:\w+)?$/
|
78
|
+
ns_name = key.split(":", 2)[1]
|
79
|
+
node.add_namespace_definition(ns_name, value)
|
80
|
+
return true
|
81
|
+
end
|
82
|
+
false
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_element(node, prefix, *args)
|
86
|
+
n = @raw.create_element(node)
|
87
|
+
if prefix
|
88
|
+
if namespace = find_prefix(prefix)
|
89
|
+
n.namespace = namespace
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
args.each do |arg|
|
94
|
+
if arg.kind_of? Hash
|
95
|
+
# Adding XML attributes
|
96
|
+
arg.each { |k,v|
|
97
|
+
key = k.to_s
|
98
|
+
n[key] = v.to_s unless apply_namespace(n, key, v)
|
99
|
+
}
|
100
|
+
elsif arg.kind_of?(Time) || arg.kind_of?(DateTime)
|
101
|
+
# Adding XML node content
|
102
|
+
n.content = arg.xmlschema
|
103
|
+
else
|
104
|
+
n.content = arg
|
105
|
+
end
|
106
|
+
end
|
107
|
+
n
|
108
|
+
end
|
109
|
+
|
110
|
+
def find_prefix(prefix)
|
111
|
+
all = [@parent] + @parent.ancestors
|
112
|
+
all.each do |a|
|
113
|
+
return a.namespace_definitions.find { |x| x.prefix == prefix.to_s } if a != @raw
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'hypertemplate' unless defined? ::Hypertemplate
|
2
|
+
|
3
|
+
module Hypertemplate
|
4
|
+
module RegistryContainer
|
5
|
+
|
6
|
+
def hypertemplate_registry
|
7
|
+
@hypertemplate || use_hypertemplate
|
8
|
+
end
|
9
|
+
|
10
|
+
def use_hypertemplate(&block)
|
11
|
+
@hypertemplate = ::Hypertemplate::Registry.new
|
12
|
+
if block_given?
|
13
|
+
yield @hypertemplate
|
14
|
+
else
|
15
|
+
@hypertemplate << ::Hypertemplate::Builder::Json
|
16
|
+
@hypertemplate << ::Hypertemplate::Builder::Xml
|
17
|
+
end
|
18
|
+
@hypertemplate
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
module ActionController
|
25
|
+
class Base
|
26
|
+
include Hypertemplate::RegistryContainer
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
module Hypertemplate
|
31
|
+
module Hook
|
32
|
+
module Rails
|
33
|
+
|
34
|
+
class Hypertemplate < ::ActionView::TemplateHandler
|
35
|
+
include ::ActionView::TemplateHandlers::Compilable
|
36
|
+
|
37
|
+
def compile(template)
|
38
|
+
"@content_type_helpers = @controller.hypertemplate_registry[self.response.content_type].helper; " +
|
39
|
+
"extend @content_type_helpers; " +
|
40
|
+
"extend Hypertemplate::Hook::Rails::Helpers; " +
|
41
|
+
"code_block = lambda { #{template.source} };" +
|
42
|
+
"builder = code_block.call; " +
|
43
|
+
"builder"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
module Helpers
|
48
|
+
# Load a partial template to execute in describe
|
49
|
+
#
|
50
|
+
# For example:
|
51
|
+
#
|
52
|
+
# Passing the current context to partial in template:
|
53
|
+
#
|
54
|
+
# member(@album) do |member, album|
|
55
|
+
# partial('member', binding)
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# in partial:
|
59
|
+
#
|
60
|
+
# member.links << link(:rel => :artists, :href => album_artists_url(album))
|
61
|
+
#
|
62
|
+
# Or passing local variables assing
|
63
|
+
#
|
64
|
+
# collection(@albums) do |collection|
|
65
|
+
# collection.members do |member, album|
|
66
|
+
# partial("member", :locals => {:member => member, :album => album})
|
67
|
+
# end
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
def partial(partial_path, caller_binding = nil)
|
71
|
+
template = _pick_partial_template(partial_path)
|
72
|
+
|
73
|
+
# Create a context to assing variables
|
74
|
+
if caller_binding.kind_of?(Hash)
|
75
|
+
Proc.new do
|
76
|
+
extend @content_type_helpers
|
77
|
+
context = eval("(class << self; self; end)", binding)
|
78
|
+
|
79
|
+
caller_binding.fetch(:locals, {}).each do |k, v|
|
80
|
+
context.send(:define_method, k.to_sym) { v }
|
81
|
+
end
|
82
|
+
|
83
|
+
partial(partial_path, binding)
|
84
|
+
end.call
|
85
|
+
else
|
86
|
+
eval(template.source, caller_binding, template.path)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def self.registry
|
94
|
+
if defined? ::ActionView::Template and ::ActionView::Template.respond_to?(:register_template_handler)
|
95
|
+
::ActionView::Template
|
96
|
+
else
|
97
|
+
if defined? ::ActionController::Base
|
98
|
+
::ActionController::Base.exempt_from_layout :hyper
|
99
|
+
::ActionController::Base.exempt_from_layout :hypertemplate
|
100
|
+
::ActionController::Base.exempt_from_layout :tokamak
|
101
|
+
end
|
102
|
+
::ActionView::Base
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
registry.register_template_handler(:hyper, Hypertemplate)
|
107
|
+
registry.register_template_handler(:hypertemplate, Hypertemplate)
|
108
|
+
registry.register_template_handler(:tokamak, Hypertemplate)
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'hypertemplate' unless defined? ::Hypertemplate
|
2
|
+
require "hypertemplate/hook/tilt"
|
3
|
+
|
4
|
+
module Rack
|
5
|
+
class Hypertemplate
|
6
|
+
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
@registry = ::Hypertemplate::Registry.new
|
10
|
+
if block_given?
|
11
|
+
yield @registry
|
12
|
+
else
|
13
|
+
@registry << ::Hypertemplate::Builder::Json
|
14
|
+
@registry << ::Hypertemplate::Builder::Xml
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
env["hypertemplate"] = @registry
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
module Hypertemplate
|
27
|
+
module Hook
|
28
|
+
module Sinatra
|
29
|
+
|
30
|
+
module ::Sinatra::Templates
|
31
|
+
|
32
|
+
def tokamak(template, options={}, locals={})
|
33
|
+
hyler(template, options, locals)
|
34
|
+
end
|
35
|
+
|
36
|
+
def hyper(template, options={}, locals={})
|
37
|
+
options.merge! :layout => false, :media_type => response["Content-Type"]
|
38
|
+
render :hyper, template, options, locals
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'hypertemplate' unless defined? ::Hypertemplate
|
2
|
+
|
3
|
+
module Hypertemplate
|
4
|
+
module Hook
|
5
|
+
module Tilt
|
6
|
+
|
7
|
+
class HypertemplateTilt
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@registry = Hypertemplate::Registry.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# unfortunately Tilt uses a global registry
|
14
|
+
def new(view = nil, line = 1, options = {}, &block)
|
15
|
+
HypertemplateTemplate.new(@registry, view, line,options, &block)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
class HypertemplateTemplate < ::Tilt::Template
|
21
|
+
|
22
|
+
def initialize(registry, view = nil, line = 1,options = {}, &block)
|
23
|
+
super(view, line, options, &block)
|
24
|
+
@registry = registry
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize_engine
|
28
|
+
return if defined?(::Hypertemplate)
|
29
|
+
require_template_library 'hypertemplate'
|
30
|
+
end
|
31
|
+
|
32
|
+
def prepare
|
33
|
+
@media_type = options[:media_type]
|
34
|
+
raise Hypertemplate::BuilderError.new("Content type required to build representation.") unless @media_type
|
35
|
+
end
|
36
|
+
|
37
|
+
def precompiled_preamble(locals)
|
38
|
+
local_assigns = super
|
39
|
+
<<-RUBY
|
40
|
+
begin
|
41
|
+
unless self.class.method_defined?(:hypertemplate_registry)
|
42
|
+
def hypertemplate_registry
|
43
|
+
env['hypertemplate']
|
44
|
+
end
|
45
|
+
end
|
46
|
+
extend hypertemplate_registry[#{@media_type.inspect}].helper
|
47
|
+
#{local_assigns}
|
48
|
+
RUBY
|
49
|
+
end
|
50
|
+
|
51
|
+
def precompiled_postamble(locals)
|
52
|
+
<<-RUBY
|
53
|
+
end
|
54
|
+
RUBY
|
55
|
+
end
|
56
|
+
|
57
|
+
def precompiled_template(locals)
|
58
|
+
data.to_str
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
::Tilt.register 'hypertemplate', HypertemplateTilt.new
|
63
|
+
::Tilt.register 'tokamak', HypertemplateTilt.new
|
64
|
+
::Tilt.register 'hyper', HypertemplateTilt.new
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Hypertemplate
|
2
|
+
class Recipes
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@recipes = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(recipe_name, &block)
|
9
|
+
@recipes[recipe_name] = block
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove(recipe_name)
|
13
|
+
@recipes.delete(recipe_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](recipe_name)
|
17
|
+
@recipes[recipe_name]
|
18
|
+
end
|
19
|
+
|
20
|
+
def list
|
21
|
+
@recipes.keys
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Hypertemplate
|
2
|
+
class Registry
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@media_types = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def <<(handler)
|
9
|
+
handler.media_types.each do |type|
|
10
|
+
@media_types[type] = handler
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](media_type)
|
15
|
+
@media_types[media_type[/^([^\s\;]+)/, 1]]
|
16
|
+
end
|
17
|
+
|
18
|
+
def []=(media_type, handler)
|
19
|
+
@media_types[media_type] = handler
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|