hobo 0.5.3
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.txt +22 -0
- data/README.txt +18 -0
- data/bin/hobo +81 -0
- data/hobo_files/plugin/CHANGES.txt +963 -0
- data/hobo_files/plugin/LICENSE.txt +22 -0
- data/hobo_files/plugin/README +4 -0
- data/hobo_files/plugin/Rakefile +11 -0
- data/hobo_files/plugin/generators/hobo/hobo_generator.rb +37 -0
- data/hobo_files/plugin/generators/hobo/templates/application.dryml +2 -0
- data/hobo_files/plugin/generators/hobo/templates/guest.rb +31 -0
- data/hobo_files/plugin/generators/hobo_front_controller/USAGE +11 -0
- data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +90 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/controller.rb +51 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +43 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/login.dryml +44 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +18 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/signup.dryml +45 -0
- data/hobo_files/plugin/generators/hobo_model/USAGE +26 -0
- data/hobo_files/plugin/generators/hobo_model/hobo_model_generator.rb +38 -0
- data/hobo_files/plugin/generators/hobo_model/templates/fixtures.yml +11 -0
- data/hobo_files/plugin/generators/hobo_model/templates/migration.rb +13 -0
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +24 -0
- data/hobo_files/plugin/generators/hobo_model/templates/unit_test.rb +10 -0
- data/hobo_files/plugin/generators/hobo_model_controller/USAGE +30 -0
- data/hobo_files/plugin/generators/hobo_model_controller/hobo_model_controller_generator.rb +43 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +5 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/view.rhtml +2 -0
- data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +51 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +436 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/default_mapping.rb +11 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/banner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_bodytop.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_01.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_02.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_03.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_04.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_bottom.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_left.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_right.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_top.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_blue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_dblue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_green.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_purple.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_red.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/logo.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/spinner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_dblue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_green.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_purple.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_red.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_01.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_02.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_03.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_04.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_bottom.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_left.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_right.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_top.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +390 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +104 -0
- data/hobo_files/plugin/generators/hobo_user_model/USAGE +26 -0
- data/hobo_files/plugin/generators/hobo_user_model/hobo_user_model_generator.rb +38 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/fixtures.yml +11 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/migration.rb +15 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +58 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/unit_test.rb +10 -0
- data/hobo_files/plugin/init.rb +44 -0
- data/hobo_files/plugin/lib/action_view_extensions/base.rb +14 -0
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +54 -0
- data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +22 -0
- data/hobo_files/plugin/lib/active_record/table_definition.rb +34 -0
- data/hobo_files/plugin/lib/extensions.rb +245 -0
- data/hobo_files/plugin/lib/extensions/test_case.rb +130 -0
- data/hobo_files/plugin/lib/hobo.rb +353 -0
- data/hobo_files/plugin/lib/hobo/HtmlString +3 -0
- data/hobo_files/plugin/lib/hobo/authenticated_user.rb +106 -0
- data/hobo_files/plugin/lib/hobo/authentication_support.rb +108 -0
- data/hobo_files/plugin/lib/hobo/composite_model.rb +66 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +134 -0
- data/hobo_files/plugin/lib/hobo/controller_helpers.rb +135 -0
- data/hobo_files/plugin/lib/hobo/core.rb +475 -0
- data/hobo_files/plugin/lib/hobo/define_tags.rb +56 -0
- data/hobo_files/plugin/lib/hobo/dryml.rb +161 -0
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +126 -0
- data/hobo_files/plugin/lib/hobo/dryml/tag_module.rb +9 -0
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +57 -0
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +586 -0
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +302 -0
- data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +19 -0
- data/hobo_files/plugin/lib/hobo/generator.rb +25 -0
- data/hobo_files/plugin/lib/hobo/html_string.rb +3 -0
- data/hobo_files/plugin/lib/hobo/lazy_hash.rb +28 -0
- data/hobo_files/plugin/lib/hobo/mapping_tags.rb +262 -0
- data/hobo_files/plugin/lib/hobo/markdown_string.rb +7 -0
- data/hobo_files/plugin/lib/hobo/model.rb +391 -0
- data/hobo_files/plugin/lib/hobo/model_controller.rb +676 -0
- data/hobo_files/plugin/lib/hobo/model_queries.rb +92 -0
- data/hobo_files/plugin/lib/hobo/model_support.rb +44 -0
- data/hobo_files/plugin/lib/hobo/password_string.rb +3 -0
- data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +78 -0
- data/hobo_files/plugin/lib/hobo/proc_binding.rb +32 -0
- data/hobo_files/plugin/lib/hobo/rapid.rb +447 -0
- data/hobo_files/plugin/lib/hobo/static_tags +92 -0
- data/hobo_files/plugin/lib/hobo/text.rb +3 -0
- data/hobo_files/plugin/lib/hobo/textile_string.rb +13 -0
- data/hobo_files/plugin/lib/hobo/undefined.rb +41 -0
- data/hobo_files/plugin/lib/hobo/undefined_access_error.rb +5 -0
- data/hobo_files/plugin/lib/hobo/where_fragment.rb +23 -0
- data/hobo_files/plugin/lib/rexml.rb +345 -0
- data/hobo_files/plugin/tags/core.dryml +6 -0
- data/hobo_files/plugin/tags/rapid.dryml +177 -0
- data/hobo_files/plugin/tags/rapid_editing.dryml +168 -0
- data/hobo_files/plugin/tags/rapid_navigation.dryml +95 -0
- data/hobo_files/plugin/tags/rapid_pages.dryml +175 -0
- data/hobo_files/plugin/tasks/environments.rake +19 -0
- data/hobo_files/plugin/tasks/hobo_tasks.rake +4 -0
- data/hobo_files/plugin/test/hobo_dryml_template_test.rb +7 -0
- data/hobo_files/plugin/test/hobo_test.rb +7 -0
- data/hobo_files/plugin/uninstall.rb +1 -0
- metadata +206 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
module Hobo::Dryml
|
|
2
|
+
|
|
3
|
+
class TemplateEnvironment
|
|
4
|
+
|
|
5
|
+
class << self
|
|
6
|
+
def inherited(subclass)
|
|
7
|
+
subclass.compiled_local_names = []
|
|
8
|
+
end
|
|
9
|
+
attr_accessor :load_time, :compiled_local_names
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
for mod in ActionView::Helpers.constants.grep(/Helper$/).map {|m| ActionView::Helpers.const_get(m)}
|
|
13
|
+
include mod
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(view_name, view)
|
|
17
|
+
@view = view
|
|
18
|
+
@view_name = view_name
|
|
19
|
+
@erb_binding = binding
|
|
20
|
+
@part_contexts = {}
|
|
21
|
+
@stack = [nil]
|
|
22
|
+
|
|
23
|
+
# Make sure the "assigns" from the controller are available (instance variables)
|
|
24
|
+
if view
|
|
25
|
+
view.assigns.each do |key, value|
|
|
26
|
+
instance_variable_set("@#{key}", value)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# copy view instance variables over
|
|
30
|
+
view.instance_variables.each do |iv|
|
|
31
|
+
instance_variable_set(iv, @view.instance_variable_get(iv))
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
attr_accessor :erb_binding, :part_contexts, :view_name
|
|
37
|
+
|
|
38
|
+
attr_reader :this_parent, :this_field, :this_type, :form_field_path, :form_this, :form_field_names
|
|
39
|
+
|
|
40
|
+
def this; @_this; end
|
|
41
|
+
|
|
42
|
+
def attr_extension(s)
|
|
43
|
+
AttributeExtensionString.new(s)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def this_field_dom_id
|
|
48
|
+
Hobo.dom_id(this_parent, this_field)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def part_context_model_id
|
|
53
|
+
if this_parent and this_parent.is_a?(ActiveRecord::Base) and this_field
|
|
54
|
+
this_field_dom_id
|
|
55
|
+
elsif this.respond_to?(:typed_id)
|
|
56
|
+
this.typed_id
|
|
57
|
+
elsif this.is_a?(Array) and !this.respond_to?(:proxy_reflection)
|
|
58
|
+
"nil"
|
|
59
|
+
else
|
|
60
|
+
Hobo.dom_id(this)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def call_part(dom_id, part_id, part_this=nil)
|
|
66
|
+
res = ''
|
|
67
|
+
if part_this
|
|
68
|
+
new_object_context(part_this) do
|
|
69
|
+
@part_contexts[dom_id] = [part_id, part_context_model_id]
|
|
70
|
+
res = send("#{part_id}_part")
|
|
71
|
+
end
|
|
72
|
+
else
|
|
73
|
+
new_context do
|
|
74
|
+
@part_contexts[dom_id] = [part_id, part_context_model_id]
|
|
75
|
+
res = send("#{part_id}_part")
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
res
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _erbout
|
|
83
|
+
@output
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def new_context
|
|
88
|
+
ctx = @output, @_this, @this_parent, @this_field, @this_type, @form_field_path
|
|
89
|
+
@output = ""
|
|
90
|
+
res = yield
|
|
91
|
+
@output, @_this, @this_parent, @this_field, @this_type, @form_field_path = ctx
|
|
92
|
+
res.to_s
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def new_object_context(new_this)
|
|
97
|
+
new_context do
|
|
98
|
+
@this_parent,@this_field,@this_type = if new_this.respond_to?(:proxy_reflection)
|
|
99
|
+
refl = new_this.proxy_reflection
|
|
100
|
+
[new_this.proxy_owner, refl.name, refl]
|
|
101
|
+
else
|
|
102
|
+
[nil, nil, new_this.class]
|
|
103
|
+
end
|
|
104
|
+
@_this = new_this
|
|
105
|
+
yield
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def new_field_context(field_path, tag_this=nil)
|
|
111
|
+
new_context do
|
|
112
|
+
path = if field_path.is_a? Array
|
|
113
|
+
field_path
|
|
114
|
+
elsif field_path.is_a? String
|
|
115
|
+
field_path.split('.')
|
|
116
|
+
else
|
|
117
|
+
[field_path]
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
obj = tag_this || this
|
|
121
|
+
for field in path
|
|
122
|
+
parent = obj
|
|
123
|
+
obj = Hobo.get_field(parent, field)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
type = if (obj.nil? or obj.respond_to?(:proxy_reflection)) and
|
|
127
|
+
parent.class.respond_to?(:field_type) and field_type = parent.class.field_type(field)
|
|
128
|
+
field_type
|
|
129
|
+
else
|
|
130
|
+
obj.class
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
@_this, @this_parent, @this_field, @this_type = obj, parent, field, type
|
|
135
|
+
@form_field_path += path if @form_field_path
|
|
136
|
+
yield
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def _tag_context(options, tagbody_proc)
|
|
142
|
+
tagbody = tagbody_proc && proc do |*args|
|
|
143
|
+
res = ''
|
|
144
|
+
block_options = args.length > 0 && args.first
|
|
145
|
+
if block_options and block_options.has_key?(:obj)
|
|
146
|
+
new_object_context(block_options[:obj]) { res = tagbody_proc.call }
|
|
147
|
+
elsif block_options and block_options.has_key?(:attr)
|
|
148
|
+
new_field_context(block_options[:attr]) { res = tagbody_proc.call }
|
|
149
|
+
else
|
|
150
|
+
new_context { res = tagbody_proc.call }
|
|
151
|
+
end
|
|
152
|
+
res
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
obj = options[:obj] == "page" ? @this : options[:obj]
|
|
156
|
+
|
|
157
|
+
if options.has_key?(:attr)
|
|
158
|
+
new_field_context(options[:attr], obj) { yield tagbody }
|
|
159
|
+
elsif options.has_key?(:obj)
|
|
160
|
+
new_object_context(obj) { yield tagbody }
|
|
161
|
+
else
|
|
162
|
+
new_context { yield tagbody }
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def with_form_context
|
|
168
|
+
@form_this = this
|
|
169
|
+
@form_field_path = []
|
|
170
|
+
@form_field_names = []
|
|
171
|
+
res = yield
|
|
172
|
+
field_names = @form_field_names
|
|
173
|
+
@form_this = @form_field_path = @form_field_names = nil
|
|
174
|
+
[res, field_names]
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def register_form_field(name)
|
|
179
|
+
@form_field_names << name
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def part_contexts_js
|
|
184
|
+
return "" if part_contexts.empty?
|
|
185
|
+
|
|
186
|
+
assigns = part_contexts.map do |dom_id, p|
|
|
187
|
+
part_id, model_id = p
|
|
188
|
+
"hoboParts.#{dom_id} = ['#{part_id}', '#{model_id}']\n"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
"<script>\nvar hoboParts = {}\n" + assigns.join + "</script>\n"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _tag_locals(options, attrs, inner_tag_names)
|
|
196
|
+
options = Hobo::Dryml.hashify_options(options)
|
|
197
|
+
options.symbolize_keys!
|
|
198
|
+
#ensure obj and attr are not in options
|
|
199
|
+
options.delete(:obj)
|
|
200
|
+
options.delete(:attr)
|
|
201
|
+
|
|
202
|
+
inner_tag_options, options = options.partition_hash(inner_tag_names.omap{to_sym})
|
|
203
|
+
|
|
204
|
+
# positional arguments never appear in the options hash
|
|
205
|
+
stripped_options = {}.update(options)
|
|
206
|
+
attrs.each {|a| stripped_options.delete(a.to_sym) }
|
|
207
|
+
attrs.map {|a| options[a.to_sym]} + [stripped_options, inner_tag_options]
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def call_replaceable_tag(name, options, external_param, &b)
|
|
212
|
+
options.delete(:replace_option)
|
|
213
|
+
|
|
214
|
+
if external_param.is_a? Hash
|
|
215
|
+
before = external_param.delete(:before_content)
|
|
216
|
+
after = external_param.delete(:after_content)
|
|
217
|
+
top = external_param.delete(:top_content)
|
|
218
|
+
bottom = external_param.delete(:bottom_content)
|
|
219
|
+
content = external_param.delete(:content)
|
|
220
|
+
options = Hobo::Dryml.merge_tag_options(options, external_param)
|
|
221
|
+
elsif !external_param.nil?
|
|
222
|
+
return external_param.to_s
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
tag = if respond_to?(name)
|
|
226
|
+
body = if content
|
|
227
|
+
proc { content }
|
|
228
|
+
elsif b && (top || bottom)
|
|
229
|
+
proc { top.to_s + b.call + bottom.to_s }
|
|
230
|
+
else
|
|
231
|
+
b
|
|
232
|
+
end
|
|
233
|
+
send(name, options, &body)
|
|
234
|
+
else
|
|
235
|
+
body = if content
|
|
236
|
+
content
|
|
237
|
+
elsif b
|
|
238
|
+
top.to_s + new_context { b.call } + bottom.to_s
|
|
239
|
+
else
|
|
240
|
+
top.to_s + bottom.to_s
|
|
241
|
+
end
|
|
242
|
+
content_tag(name, body, options)
|
|
243
|
+
end
|
|
244
|
+
before.to_s + tag.to_s + after.to_s
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def call_replaceable_content_tag(name, options, external_param, &b)
|
|
249
|
+
options.delete(:content_option)
|
|
250
|
+
|
|
251
|
+
if external_param.is_a? Hash
|
|
252
|
+
content = external_param.delete(:content)
|
|
253
|
+
top = external_param.delete(:top_content)
|
|
254
|
+
bottom = external_param.delete(:bottom_content)
|
|
255
|
+
external_param.delete(:before_content)
|
|
256
|
+
external_param.delete(:after_content)
|
|
257
|
+
options = Hobo::Dryml.merge_tag_options(options, external_param)
|
|
258
|
+
elsif !external_param.nil?
|
|
259
|
+
content = external_param.to_s
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# If there's no body, and no content provided externally, remove
|
|
263
|
+
# the tag altogether
|
|
264
|
+
return if b.nil? and content.nil?
|
|
265
|
+
|
|
266
|
+
tag = if respond_to?(name)
|
|
267
|
+
body = if content
|
|
268
|
+
proc { content }
|
|
269
|
+
elsif b && (top || bottom)
|
|
270
|
+
proc { top.to_s + b.call + bottom.to_s }
|
|
271
|
+
else
|
|
272
|
+
b
|
|
273
|
+
end
|
|
274
|
+
send(name, options, &body)
|
|
275
|
+
else
|
|
276
|
+
body = if content
|
|
277
|
+
content
|
|
278
|
+
elsif b
|
|
279
|
+
top.to_s + new_context { b.call } + bottom.to_s
|
|
280
|
+
else
|
|
281
|
+
top.to_s + bottom.to_s
|
|
282
|
+
end
|
|
283
|
+
content_tag(name, body, options)
|
|
284
|
+
end
|
|
285
|
+
tag.to_s
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
def render_tag(tag_name, options)
|
|
290
|
+
(send(tag_name, options) + part_contexts_js).strip
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def method_missing(name, *args)
|
|
295
|
+
@view.send(name, *args)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Hobo::Dryml
|
|
2
|
+
|
|
3
|
+
class TemplateHandler
|
|
4
|
+
|
|
5
|
+
def initialize(view)
|
|
6
|
+
@view = view
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def render(src, local_assigns)
|
|
10
|
+
renderer = Hobo::Dryml.page_renderer(@view, local_assigns.keys)
|
|
11
|
+
s = renderer.render_page(@view.assigns["this"] || local_assigns[:this], local_assigns)
|
|
12
|
+
# Important to strip whitespace, or the browser hangs around for ages (FF2)
|
|
13
|
+
|
|
14
|
+
s.strip
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'find'
|
|
2
|
+
|
|
3
|
+
class Hobo::Generator < Rails::Generator::Base
|
|
4
|
+
|
|
5
|
+
def with_source_in(path)
|
|
6
|
+
root = source_path(path)
|
|
7
|
+
Find.find(root) do |f|
|
|
8
|
+
Find.prune if File.basename(f) == ".svn"
|
|
9
|
+
full_path = f[(source_root.length)..-1]
|
|
10
|
+
rel_path = f[(root.length)..-1]
|
|
11
|
+
yield full_path, rel_path
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def create_all(m, src, dest)
|
|
16
|
+
with_source_in(src) do |full, rel|
|
|
17
|
+
if File.directory?(source_path(full))
|
|
18
|
+
m.directory File.join(dest, rel)
|
|
19
|
+
else
|
|
20
|
+
m.file full, File.join(dest, rel)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class Hobo::LazyHash < Hash
|
|
2
|
+
|
|
3
|
+
def initialize(hash=nil)
|
|
4
|
+
if hash.is_a?(Hash)
|
|
5
|
+
update(hash)
|
|
6
|
+
else
|
|
7
|
+
super
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def [](key)
|
|
12
|
+
val = super
|
|
13
|
+
if val.is_a?(Proc)
|
|
14
|
+
self[val] = val.call
|
|
15
|
+
else
|
|
16
|
+
val
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inspect
|
|
21
|
+
"#<LazyHash:#{object_id} #{keys.inspect}>"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_s
|
|
25
|
+
inspect
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
module Hobo
|
|
2
|
+
module MappingTags
|
|
3
|
+
|
|
4
|
+
class InvalidMappingError < RuntimeError; end
|
|
5
|
+
|
|
6
|
+
class TagOrSelector
|
|
7
|
+
|
|
8
|
+
def initialize(name, all_mappings)
|
|
9
|
+
@_name = name
|
|
10
|
+
@_dot_names = []
|
|
11
|
+
@_selectors = []
|
|
12
|
+
|
|
13
|
+
# Keep a reference to the set of mappings for the whole
|
|
14
|
+
# mapping_tags do ... end, so we can remove self if it turns out
|
|
15
|
+
# to be an AttributeValueSelector
|
|
16
|
+
@all_mappings = all_mappings
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
attr_accessor :_name, :_selectors, :_dot_names
|
|
20
|
+
|
|
21
|
+
def method_missing(name)
|
|
22
|
+
raise NoMethodError.new("undefined method: #{name}") if name.to_s =~ /^_|[!?=]$/
|
|
23
|
+
_dot_names << name
|
|
24
|
+
self
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def [](*selectors)
|
|
29
|
+
raise InvalidMappingError.new unless _selectors.empty?
|
|
30
|
+
|
|
31
|
+
@_selectors = selectors.omap {_to_selector}
|
|
32
|
+
self
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _to_selector
|
|
37
|
+
raise InvalidMappingError.new unless _dot_names.empty? and _selectors.empty?
|
|
38
|
+
AttributeSelector.new(_name)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def ==(rhs)
|
|
43
|
+
raise InvalidMappingError.new unless _selectors.empty? and _dot_names.empty?
|
|
44
|
+
AttributeValueSelector.new(_name, rhs)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def >>(rhs)
|
|
49
|
+
@all_mappings << Mapping.new(self, rhs)
|
|
50
|
+
nil
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class AttributeSelector
|
|
56
|
+
|
|
57
|
+
def initialize(attribute)
|
|
58
|
+
@attribute = attribute
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def compile
|
|
63
|
+
"options[:#{@attribute}]"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class AttributeValueSelector
|
|
68
|
+
|
|
69
|
+
def initialize(name, value)
|
|
70
|
+
@name = name
|
|
71
|
+
@value = value
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
attr_reader :name, :value
|
|
75
|
+
|
|
76
|
+
def compile
|
|
77
|
+
"(options[:#{@name}] == #{@value.inspect})"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def _to_selector
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class Mapping
|
|
88
|
+
|
|
89
|
+
def initialize(pattern, result)
|
|
90
|
+
raise InvalidMappingError.new unless result._selectors.empty? and pattern._dot_names.length <= 1
|
|
91
|
+
@pattern = pattern
|
|
92
|
+
@result = result
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
attr_reader :pattern, :result
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def pattern_tag_name
|
|
99
|
+
pattern._name
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def pattern_predicate
|
|
104
|
+
clauses = (pattern._selectors || []).omap{compile}
|
|
105
|
+
type_name = pattern._dot_names.first
|
|
106
|
+
clauses << "selector_type && (#{type_name.to_s.camelize} <= selector_type)" if type_name
|
|
107
|
+
!clauses.empty? && "proc {|options| #{clauses.join(' and ')}}"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def result_tag_name
|
|
112
|
+
result._name
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def result_css_classes
|
|
117
|
+
result._dot_names
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class MappingDSL
|
|
125
|
+
|
|
126
|
+
def initialize
|
|
127
|
+
@_mappings = []
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
attr_reader :_mappings
|
|
131
|
+
|
|
132
|
+
def standard_mappings
|
|
133
|
+
instance_eval do
|
|
134
|
+
intro >> div.intro
|
|
135
|
+
maincol >> div.maincol
|
|
136
|
+
sidecol >> div.sidecol
|
|
137
|
+
panel >> div.panel
|
|
138
|
+
section >> div.section.foo
|
|
139
|
+
|
|
140
|
+
fields >> table.fields
|
|
141
|
+
field >> tr.field
|
|
142
|
+
fl >> td.field_label
|
|
143
|
+
fd >> td.field_data
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def method_missing(name, &b)
|
|
148
|
+
raise NoMethodError.new("undefined method: #{name}") if name.to_s =~ /^_|[!?=]$/
|
|
149
|
+
TagOrSelector.new(name, @_mappings)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
(Object.instance_methods +
|
|
155
|
+
Object.private_instance_methods +
|
|
156
|
+
Object.protected_instance_methods).each do |m|
|
|
157
|
+
MappingDSL.send(:undef_method, m) unless
|
|
158
|
+
%w{initialize method_missing instance_eval standard_mappings}.include?(m) || m.starts_with?('_')
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def self.define_mapping_tag(mapping, mod)
|
|
163
|
+
def_name = mapping.pattern_tag_name
|
|
164
|
+
pred = mapping.pattern_predicate
|
|
165
|
+
result_tag_name = mapping.result_tag_name
|
|
166
|
+
result_css_classes = mapping.result_css_classes
|
|
167
|
+
|
|
168
|
+
static_tag_name = result_tag_name if result_tag_name.to_s.in?(Hobo.static_tags)
|
|
169
|
+
|
|
170
|
+
if def_name == result_tag_name
|
|
171
|
+
result_tag_name = "#{def_name}_unmapped"
|
|
172
|
+
if def_name.to_s.in?(mod.instance_methods) and result_tag_name.not_in?(mod.instance_methods)
|
|
173
|
+
mod.send(:alias_method, result_tag_name, def_name)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
if pred and !mod.predicate_has_default?(def_name)
|
|
177
|
+
# Make sure the old tag method is called when the predicate is false
|
|
178
|
+
mod.module_eval "defp(:#{def_name}) { |options, block| #{result_tag_name}(options, &block) }"
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# puts "map: #{def_name}[#{pred}] -> #{result_tag_name} (#{result_css_classes * ' '}) #{static_tag_name}"
|
|
183
|
+
|
|
184
|
+
def_line = if !pred.blank?
|
|
185
|
+
"defp :#{def_name}, (#{pred}) do |options, block|"
|
|
186
|
+
elsif mod.predicate_method?(def_name)
|
|
187
|
+
# be sure not to overwrite the predicate dispatch method
|
|
188
|
+
"defp :#{def_name} do |options, block|"
|
|
189
|
+
else
|
|
190
|
+
"def #{def_name}(options={}, &block)"
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
add_classes = if result_css_classes.empty?
|
|
194
|
+
""
|
|
195
|
+
else
|
|
196
|
+
"options = add_classes(options, *#{result_css_classes.inspect})"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
no_method_fallback = if static_tag_name
|
|
200
|
+
"content_tag('#{static_tag_name}', tagbody && tagbody.call, options)"
|
|
201
|
+
else
|
|
202
|
+
"raise NoMethodError.new('undefined method: #{result_tag_name}')"
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
mod.module_eval(x = <<-END, __FILE__, __LINE__+1)
|
|
206
|
+
#{def_line}
|
|
207
|
+
_tag_context(options, block) do |tagbody|
|
|
208
|
+
#{add_classes}
|
|
209
|
+
if respond_to?('#{result_tag_name}')
|
|
210
|
+
#{result_tag_name}(options, &block)
|
|
211
|
+
else
|
|
212
|
+
#{no_method_fallback}
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
END
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def self.make_mappings(&b)
|
|
221
|
+
d = MappingDSL.new
|
|
222
|
+
d.instance_eval(&b)
|
|
223
|
+
d._mappings
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def self.map(&b)
|
|
228
|
+
@mappings = make_mappings(&b)
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def self.apply_mappings(mod)
|
|
233
|
+
mod.send(:include, PredicateDispatch) unless PredicateDispatch.in?(mod.included_modules)
|
|
234
|
+
@mappings.each {|m| define_mapping_tag(m, mod) }
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def self.apply_standard_mappings(mod)
|
|
239
|
+
mod.send(:include, PredicateDispatch) unless PredicateDispatch.in?(mod.included_modules)
|
|
240
|
+
standard_mappings = make_mappings do
|
|
241
|
+
intro >> div.intro
|
|
242
|
+
main >> div.main
|
|
243
|
+
maincol >> div.maincol
|
|
244
|
+
sidecol >> div.sidecol
|
|
245
|
+
panel >> div.panel
|
|
246
|
+
section >> div.section
|
|
247
|
+
|
|
248
|
+
fields >> table.fields
|
|
249
|
+
field >> tr.field
|
|
250
|
+
fl >> td.field_label
|
|
251
|
+
fd >> td.field_data
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
for mapping in standard_mappings
|
|
255
|
+
define_mapping_tag(mapping, mod) unless mapping.pattern_tag_name.to_s.in?(mod.instance_methods)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
end
|