raw 0.49.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/doc/CONTRIBUTORS +106 -0
- data/doc/LICENSE +32 -0
- data/doc/coding_conventions.txt +11 -0
- data/lib/raw.rb +42 -0
- data/lib/raw/adapter.rb +113 -0
- data/lib/raw/adapter/cgi.rb +41 -0
- data/lib/raw/adapter/fastcgi.rb +48 -0
- data/lib/raw/adapter/mongrel.rb +146 -0
- data/lib/raw/adapter/script.rb +94 -0
- data/lib/raw/adapter/webrick.rb +144 -0
- data/lib/raw/adapter/webrick/vcr.rb +91 -0
- data/lib/raw/cgi.rb +323 -0
- data/lib/raw/cgi/cookie.rb +47 -0
- data/lib/raw/cgi/http.rb +62 -0
- data/lib/raw/compiler.rb +138 -0
- data/lib/raw/compiler/filter/cleanup.rb +21 -0
- data/lib/raw/compiler/filter/elements.rb +166 -0
- data/lib/raw/compiler/filter/elements/element.rb +210 -0
- data/lib/raw/compiler/filter/localization.rb +23 -0
- data/lib/raw/compiler/filter/markup.rb +32 -0
- data/lib/raw/compiler/filter/morph.rb +123 -0
- data/lib/raw/compiler/filter/morph/each.rb +34 -0
- data/lib/raw/compiler/filter/morph/for.rb +11 -0
- data/lib/raw/compiler/filter/morph/if.rb +26 -0
- data/lib/raw/compiler/filter/morph/selected_if.rb +43 -0
- data/lib/raw/compiler/filter/morph/standard.rb +55 -0
- data/lib/raw/compiler/filter/morph/times.rb +27 -0
- data/lib/raw/compiler/filter/script.rb +116 -0
- data/lib/raw/compiler/filter/squeeze.rb +16 -0
- data/lib/raw/compiler/filter/static_include.rb +74 -0
- data/lib/raw/compiler/filter/template.rb +121 -0
- data/lib/raw/compiler/reloader.rb +96 -0
- data/lib/raw/context.rb +154 -0
- data/lib/raw/context/flash.rb +157 -0
- data/lib/raw/context/global.rb +88 -0
- data/lib/raw/context/request.rb +338 -0
- data/lib/raw/context/response.rb +57 -0
- data/lib/raw/context/session.rb +198 -0
- data/lib/raw/context/session/drb.rb +11 -0
- data/lib/raw/context/session/file.rb +15 -0
- data/lib/raw/context/session/memcached.rb +13 -0
- data/lib/raw/context/session/memory.rb +12 -0
- data/lib/raw/context/session/og.rb +15 -0
- data/lib/raw/context/session/pstore.rb +13 -0
- data/lib/raw/control.rb +18 -0
- data/lib/raw/control/attribute.rb +91 -0
- data/lib/raw/control/attribute/checkbox.rb +25 -0
- data/lib/raw/control/attribute/datetime.rb +21 -0
- data/lib/raw/control/attribute/file.rb +20 -0
- data/lib/raw/control/attribute/fixnum.rb +26 -0
- data/lib/raw/control/attribute/float.rb +26 -0
- data/lib/raw/control/attribute/options.rb +38 -0
- data/lib/raw/control/attribute/password.rb +16 -0
- data/lib/raw/control/attribute/text.rb +16 -0
- data/lib/raw/control/attribute/textarea.rb +16 -0
- data/lib/raw/control/none.rb +16 -0
- data/lib/raw/control/relation.rb +59 -0
- data/lib/raw/control/relation/belongs_to.rb +0 -0
- data/lib/raw/control/relation/has_many.rb +97 -0
- data/lib/raw/control/relation/joins_many.rb +0 -0
- data/lib/raw/control/relation/many_to_many.rb +0 -0
- data/lib/raw/control/relation/refers_to.rb +29 -0
- data/lib/raw/controller.rb +37 -0
- data/lib/raw/controller/publishable.rb +160 -0
- data/lib/raw/dispatcher.rb +209 -0
- data/lib/raw/dispatcher/format.rb +108 -0
- data/lib/raw/dispatcher/format/atom.rb +31 -0
- data/lib/raw/dispatcher/format/css.rb +0 -0
- data/lib/raw/dispatcher/format/html.rb +42 -0
- data/lib/raw/dispatcher/format/json.rb +31 -0
- data/lib/raw/dispatcher/format/rss.rb +33 -0
- data/lib/raw/dispatcher/format/xoxo.rb +31 -0
- data/lib/raw/dispatcher/mounter.rb +60 -0
- data/lib/raw/dispatcher/router.rb +111 -0
- data/lib/raw/errors.rb +19 -0
- data/lib/raw/helper.rb +86 -0
- data/lib/raw/helper/benchmark.rb +23 -0
- data/lib/raw/helper/buffer.rb +60 -0
- data/lib/raw/helper/cookie.rb +32 -0
- data/lib/raw/helper/debug.rb +28 -0
- data/lib/raw/helper/default.rb +16 -0
- data/lib/raw/helper/feed.rb +451 -0
- data/lib/raw/helper/form.rb +284 -0
- data/lib/raw/helper/javascript.rb +59 -0
- data/lib/raw/helper/layout.rb +40 -0
- data/lib/raw/helper/navigation.rb +87 -0
- data/lib/raw/helper/pager.rb +305 -0
- data/lib/raw/helper/table.rb +247 -0
- data/lib/raw/helper/xhtml.rb +218 -0
- data/lib/raw/helper/xml.rb +125 -0
- data/lib/raw/mixin/magick.rb +35 -0
- data/lib/raw/mixin/sweeper.rb +71 -0
- data/lib/raw/mixin/thumbnails.rb +1 -0
- data/lib/raw/mixin/webfile.rb +165 -0
- data/lib/raw/render.rb +271 -0
- data/lib/raw/render/builder.rb +26 -0
- data/lib/raw/render/caching.rb +81 -0
- data/lib/raw/render/call.rb +43 -0
- data/lib/raw/render/send_file.rb +46 -0
- data/lib/raw/render/stream.rb +39 -0
- data/lib/raw/scaffold.rb +13 -0
- data/lib/raw/scaffold/controller.rb +25 -0
- data/lib/raw/scaffold/model.rb +157 -0
- data/lib/raw/test.rb +5 -0
- data/lib/raw/test/assertions.rb +169 -0
- data/lib/raw/test/context.rb +55 -0
- data/lib/raw/test/testcase.rb +79 -0
- data/lib/raw/util/attr.rb +128 -0
- data/lib/raw/util/encode_uri.rb +149 -0
- data/lib/raw/util/html_filter.rb +538 -0
- data/lib/raw/util/markup.rb +130 -0
- data/test/glue/tc_webfile.rb +1 -0
- data/test/nitro/CONFIG.rb +3 -0
- data/test/nitro/adapter/raw_post1.bin +9 -0
- data/test/nitro/adapter/tc_webrick.rb +16 -0
- data/test/nitro/cgi/tc_cookie.rb +14 -0
- data/test/nitro/cgi/tc_request.rb +61 -0
- data/test/nitro/compiler/tc_client_morpher.rb +47 -0
- data/test/nitro/compiler/tc_compiler.rb +25 -0
- data/test/nitro/dispatcher/tc_mounter.rb +47 -0
- data/test/nitro/helper/tc_feed.rb +135 -0
- data/test/nitro/helper/tc_navbar.rb +74 -0
- data/test/nitro/helper/tc_pager.rb +35 -0
- data/test/nitro/helper/tc_table.rb +68 -0
- data/test/nitro/helper/tc_xhtml.rb +19 -0
- data/test/nitro/tc_caching.rb +19 -0
- data/test/nitro/tc_cgi.rb +222 -0
- data/test/nitro/tc_context.rb +17 -0
- data/test/nitro/tc_controller.rb +103 -0
- data/test/nitro/tc_controller_aspect.rb +32 -0
- data/test/nitro/tc_controller_params.rb +885 -0
- data/test/nitro/tc_dispatcher.rb +109 -0
- data/test/nitro/tc_element.rb +85 -0
- data/test/nitro/tc_flash.rb +59 -0
- data/test/nitro/tc_helper.rb +47 -0
- data/test/nitro/tc_render.rb +119 -0
- data/test/nitro/tc_router.rb +61 -0
- data/test/nitro/tc_server.rb +35 -0
- data/test/nitro/tc_session.rb +66 -0
- data/test/nitro/tc_template.rb +71 -0
- data/test/nitro/util/tc_encode_url.rb +87 -0
- data/test/nitro/util/tc_markup.rb +31 -0
- data/test/public/blog/another/very_litle/index.xhtml +1 -0
- data/test/public/blog/inc1.xhtml +2 -0
- data/test/public/blog/inc2.xhtml +1 -0
- data/test/public/blog/list.xhtml +9 -0
- data/test/public/dummy_mailer/registration.xhtml +5 -0
- metadata +244 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
module Raw
|
|
2
|
+
|
|
3
|
+
# Encapsulates a HTTP Cookie.
|
|
4
|
+
|
|
5
|
+
class Cookie
|
|
6
|
+
attr_reader :name
|
|
7
|
+
attr_accessor :value, :version
|
|
8
|
+
attr_accessor :domain, :path, :secure
|
|
9
|
+
attr_accessor :comment, :max_age
|
|
10
|
+
|
|
11
|
+
def initialize(name = nil, value = nil, expires = nil)
|
|
12
|
+
@name = name
|
|
13
|
+
@value = value
|
|
14
|
+
self.expires = expires
|
|
15
|
+
@version = 0 # Netscape Cookie THINK: maybe should make this 1 ??
|
|
16
|
+
@path = "/" # gmosx: KEEP this!
|
|
17
|
+
@domain = @secure = @comment = @max_age = nil
|
|
18
|
+
@discard = @port = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Set the cookie expiration.
|
|
22
|
+
|
|
23
|
+
def expires=(t)
|
|
24
|
+
@expires = t && (t.is_a?(Time) ? t.httpdate : t.to_s)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# When the cookie expires.
|
|
28
|
+
|
|
29
|
+
def expires
|
|
30
|
+
@expires && Time.parse(@expires)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_s
|
|
34
|
+
str = "#{@name}=#{@value}"
|
|
35
|
+
str << "; Version=#{@version}" if @version > 0
|
|
36
|
+
str << "; Domain=#{@domain}" if @domain
|
|
37
|
+
str << "; Expires=#{@expires}" if @expires
|
|
38
|
+
str << "; Max-Age=#{@max_age}" if @max_age
|
|
39
|
+
str << "; Comment=#{@comment}" if @comment
|
|
40
|
+
str << "; Path=#{@path}" if @path
|
|
41
|
+
str << "; Secure" if @secure
|
|
42
|
+
return str
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
data/lib/raw/cgi/http.rb
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module Raw
|
|
2
|
+
|
|
3
|
+
# Various HTTP related constants and utilities.
|
|
4
|
+
|
|
5
|
+
module Http
|
|
6
|
+
|
|
7
|
+
# HTTP protocol EOL constants.
|
|
8
|
+
|
|
9
|
+
CR = "\x0d"
|
|
10
|
+
LF = "\x0a"
|
|
11
|
+
CRLF = "\x0d\x0a"
|
|
12
|
+
EOL = CRLF
|
|
13
|
+
|
|
14
|
+
# Constants for readable code.
|
|
15
|
+
|
|
16
|
+
STATUS_OK = 200
|
|
17
|
+
STATUS_PARTIAL_CONTENT = 206
|
|
18
|
+
STATUS_MOVED = 301
|
|
19
|
+
STATUS_REDIRECT = 302
|
|
20
|
+
STATUS_SEE_OTHER = 303
|
|
21
|
+
STATUS_SEE_OTHER_307 = 307
|
|
22
|
+
STATUS_NOT_MODIFIED = 304
|
|
23
|
+
STATUS_BAD_REQUEST = 400
|
|
24
|
+
STATUS_AUTH_REQUIRED = 401
|
|
25
|
+
STATUS_FORBIDDEN = 403
|
|
26
|
+
STATUS_NOT_FOUND = 404
|
|
27
|
+
STATUS_METHOD_NOT_ALLOWED = 405
|
|
28
|
+
STATUS_NOT_ACCEPTABLE = 406
|
|
29
|
+
STATUS_LENGTH_REQUIRED = 411
|
|
30
|
+
STATUS_PRECONDITION_FAILED = 412
|
|
31
|
+
STATUS_SERVER_ERROR = 500
|
|
32
|
+
STATUS_NOT_IMPLEMENTED = 501
|
|
33
|
+
STATUS_BAD_GATEWAY = 502
|
|
34
|
+
STATUS_VARIANT_ALSO_VARIES = 506
|
|
35
|
+
|
|
36
|
+
# Hash to allow id to description maping.
|
|
37
|
+
|
|
38
|
+
STATUS_STRINGS = {
|
|
39
|
+
200 => "OK",
|
|
40
|
+
206 => "Partial Content",
|
|
41
|
+
300 => "Multiple Choices",
|
|
42
|
+
301 => "Moved Permanently",
|
|
43
|
+
302 => "Found",
|
|
44
|
+
303 => "See other", # gmosx: VERIFY THIS
|
|
45
|
+
304 => "Not Modified",
|
|
46
|
+
307 => "See other 07", # gmosx: VERIFY THIS
|
|
47
|
+
400 => "Bad Request",
|
|
48
|
+
401 => "Authorization Required",
|
|
49
|
+
403 => "Forbidden",
|
|
50
|
+
404 => "Not Found",
|
|
51
|
+
405 => "Method Not Allowed",
|
|
52
|
+
406 => "Not Acceptable",
|
|
53
|
+
411 => "Length Required",
|
|
54
|
+
412 => "Precondition Failed",
|
|
55
|
+
500 => "Internal Server Error",
|
|
56
|
+
501 => "Method Not Implemented",
|
|
57
|
+
502 => "Bad Gateway",
|
|
58
|
+
506 => "Variant Also Negotiates"
|
|
59
|
+
}
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
data/lib/raw/compiler.rb
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require "raw/compiler/reloader"
|
|
2
|
+
|
|
3
|
+
module Raw
|
|
4
|
+
|
|
5
|
+
# The Compiler dynamically generates action methods for the
|
|
6
|
+
# Controllers.
|
|
7
|
+
|
|
8
|
+
class Compiler
|
|
9
|
+
|
|
10
|
+
# A collection of the loaded template files.
|
|
11
|
+
|
|
12
|
+
attr_accessor :templates
|
|
13
|
+
|
|
14
|
+
# The reloader monitors and reloads code and template files.
|
|
15
|
+
|
|
16
|
+
attr_accessor :reloader
|
|
17
|
+
|
|
18
|
+
# Initialize the compiler.
|
|
19
|
+
|
|
20
|
+
def initialize(application)
|
|
21
|
+
@application = application
|
|
22
|
+
@reloader = Reloader.new(application)
|
|
23
|
+
@templates = []
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# This method compiles missing Controller methods. Only handles
|
|
27
|
+
# xxx___super and xxx___{format}___view methods.
|
|
28
|
+
|
|
29
|
+
def compile(controller, meth)
|
|
30
|
+
meth = meth.to_s
|
|
31
|
+
|
|
32
|
+
if meth =~ %r{___super$}
|
|
33
|
+
compile_super(controller, meth)
|
|
34
|
+
elsif meth =~ %r{___view$}
|
|
35
|
+
compile_view(controller, meth)
|
|
36
|
+
else
|
|
37
|
+
return false
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Compile the action super-method for the given URI. This
|
|
42
|
+
# super-method calls the action and view sub-methods. The
|
|
43
|
+
# action sub-method is typically provided by the controller.
|
|
44
|
+
#
|
|
45
|
+
# In a sense, the super-method orchestrates the action and
|
|
46
|
+
# view sub-methods to handle the given URI.
|
|
47
|
+
|
|
48
|
+
def compile_super(controller, meth)
|
|
49
|
+
action = meth.gsub(%r{___super$}, "")
|
|
50
|
+
|
|
51
|
+
Logger.debug "Compiling '#{action}' super-method" if $DBG
|
|
52
|
+
|
|
53
|
+
if controller.action_or_template?(action, Context.current.format)
|
|
54
|
+
|
|
55
|
+
# This is the actual control super method that calls
|
|
56
|
+
# the action code and the template for this format.
|
|
57
|
+
|
|
58
|
+
code = lambda do |params|
|
|
59
|
+
@context.format.before_action(self, @context)
|
|
60
|
+
|
|
61
|
+
@action = action.to_sym
|
|
62
|
+
|
|
63
|
+
# Call the action sub-method.
|
|
64
|
+
|
|
65
|
+
send(action, *params) if respond_to? action
|
|
66
|
+
|
|
67
|
+
# Call the view sub-method (render the template).
|
|
68
|
+
|
|
69
|
+
send("#{action}___#{@context.format}___view")
|
|
70
|
+
|
|
71
|
+
@context.format.after_action(self, @context)
|
|
72
|
+
|
|
73
|
+
cache_output()
|
|
74
|
+
end # lambda
|
|
75
|
+
|
|
76
|
+
controller.send(:define_method, meth, code)
|
|
77
|
+
controller.send(:private, meth)
|
|
78
|
+
|
|
79
|
+
return true
|
|
80
|
+
else
|
|
81
|
+
return false
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Compile the view sub-method for the given URI.
|
|
86
|
+
#--
|
|
87
|
+
# The sub-method is always generated, if no template is found
|
|
88
|
+
# it is just a nop method.
|
|
89
|
+
#
|
|
90
|
+
# TODO: cache the generated files (reuse the cached files
|
|
91
|
+
# to extract error regions)
|
|
92
|
+
#++
|
|
93
|
+
|
|
94
|
+
def compile_view(controller, meth)
|
|
95
|
+
md = meth.match(%r{(.*)___(.*)___view})
|
|
96
|
+
action, format = md[1], md[2]
|
|
97
|
+
|
|
98
|
+
format = @application.dispatcher.formats[format]
|
|
99
|
+
|
|
100
|
+
Logger.debug "Compiling '#{action}' view sub-method [format: #{format}]" if $DBG
|
|
101
|
+
|
|
102
|
+
unless controller.instance_methods.include? meth
|
|
103
|
+
# The view method is missing. The Compiler will try to
|
|
104
|
+
# use a template or generate an empty view method.
|
|
105
|
+
|
|
106
|
+
template = nil
|
|
107
|
+
|
|
108
|
+
if path = controller.template_path(action, format)
|
|
109
|
+
# Keep a ref of this template for the reloader.
|
|
110
|
+
|
|
111
|
+
@templates = @templates.push(path).uniq
|
|
112
|
+
|
|
113
|
+
# Read the template source.
|
|
114
|
+
|
|
115
|
+
template = File.read(path)
|
|
116
|
+
|
|
117
|
+
# Apply the template filters.
|
|
118
|
+
|
|
119
|
+
unless template.blank?
|
|
120
|
+
template = format.filter_template(template)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
controller.class_eval <<-EOCODE # , path, 0
|
|
125
|
+
def #{meth}
|
|
126
|
+
#{template}
|
|
127
|
+
end
|
|
128
|
+
EOCODE
|
|
129
|
+
|
|
130
|
+
controller.send(:private, meth)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
return true
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Raw
|
|
2
|
+
|
|
3
|
+
# Cleanup the xhtml code generated by REXML used in other
|
|
4
|
+
# filters.
|
|
5
|
+
|
|
6
|
+
class CleanupFilter
|
|
7
|
+
|
|
8
|
+
def apply(source)
|
|
9
|
+
source = source.dup
|
|
10
|
+
|
|
11
|
+
elements = "input|img|br|hr|link|style|render|include|inject|base|meta"
|
|
12
|
+
source.gsub! /<textarea ([^>]*)><\/textarea>/, '<textarea \1>#{}</textarea>'
|
|
13
|
+
source.gsub! /<(#{elements}) ([^>]*)><\/\1>/, '<\1 \2 />'
|
|
14
|
+
source.gsub! /<(#{elements})><\/\1>/, '<\1 />'
|
|
15
|
+
|
|
16
|
+
return source
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
require "rexml/document"
|
|
2
|
+
require "rexml/streamlistener"
|
|
3
|
+
|
|
4
|
+
require "facets/core/kernel/constant"
|
|
5
|
+
|
|
6
|
+
require "raw/compiler/filter/elements/element"
|
|
7
|
+
|
|
8
|
+
module Raw
|
|
9
|
+
|
|
10
|
+
# A filter that transforms user defined Elements. Elements
|
|
11
|
+
# are custom tags that are used as macros or to implement
|
|
12
|
+
# skins.
|
|
13
|
+
#
|
|
14
|
+
# === Example
|
|
15
|
+
#
|
|
16
|
+
# <Page>
|
|
17
|
+
# the
|
|
18
|
+
# </Page>
|
|
19
|
+
|
|
20
|
+
class ElementsFilter
|
|
21
|
+
|
|
22
|
+
class Listener # :nodoc: all
|
|
23
|
+
include REXML::StreamListener
|
|
24
|
+
|
|
25
|
+
PREFIX_RE = /^#{Element.prefix}:/
|
|
26
|
+
CAPITALIZED_RE = /^[A-Z]/
|
|
27
|
+
|
|
28
|
+
attr_accessor :buffer
|
|
29
|
+
|
|
30
|
+
def initialize
|
|
31
|
+
super()
|
|
32
|
+
@buffer = ''
|
|
33
|
+
@stack = []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def tag_start(name, attributes)
|
|
37
|
+
if klass = is_element?(name)
|
|
38
|
+
obj = klass.new
|
|
39
|
+
|
|
40
|
+
attributes.each do | k, v |
|
|
41
|
+
obj.instance_variable_set("@#{k}", v)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@stack.push [obj, @buffer, @parent]
|
|
45
|
+
|
|
46
|
+
@buffer = obj._text
|
|
47
|
+
@parent.add_child(obj) if @parent
|
|
48
|
+
|
|
49
|
+
@parent = obj
|
|
50
|
+
else # This is a static element.
|
|
51
|
+
attrs = []
|
|
52
|
+
|
|
53
|
+
attributes.each do | k, v |
|
|
54
|
+
attrs << %|#{k}="#{v}"|
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
attrs = attrs.empty? ? nil : " #{attrs.join(' ')}"
|
|
58
|
+
|
|
59
|
+
@buffer << "<#{name}#{attrs}>"
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def tag_end(name)
|
|
64
|
+
if is_element? name
|
|
65
|
+
obj, @buffer, @parent = @stack.pop
|
|
66
|
+
@buffer << obj.render
|
|
67
|
+
else
|
|
68
|
+
@buffer << "</#{name}>"
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Check if a tag is an Element. If found, it also tries to
|
|
73
|
+
# auto-extend the klass. Returns the Element class if found.
|
|
74
|
+
#
|
|
75
|
+
# Tries many classes in the following order:
|
|
76
|
+
#
|
|
77
|
+
# * Controller::XXX
|
|
78
|
+
# * {controller.ann(:self, :element_namespace)}::XXX
|
|
79
|
+
# * Nitro::Element::XXX
|
|
80
|
+
|
|
81
|
+
def is_element?(name)
|
|
82
|
+
controller = Controller.current
|
|
83
|
+
|
|
84
|
+
return false unless name =~ PREFIX_RE or name =~ CAPITALIZED_RE
|
|
85
|
+
|
|
86
|
+
name = name.gsub(PREFIX_RE,'').camelize if name =~ PREFIX_RE
|
|
87
|
+
|
|
88
|
+
# Try to use Controller::xxx
|
|
89
|
+
# gmosx, THINK: this looks a bit dangerous to me!
|
|
90
|
+
|
|
91
|
+
begin
|
|
92
|
+
# gmosx, FIXME: Class.by_name also returns top level
|
|
93
|
+
# classes, how can we fix this?
|
|
94
|
+
|
|
95
|
+
klass = constant("#{controller}::#{name}")
|
|
96
|
+
rescue
|
|
97
|
+
# drink it!
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Try to use the Controller's :element_namespace annotation
|
|
101
|
+
|
|
102
|
+
if namespace = controller.ann(:self, :element_namespace)
|
|
103
|
+
begin
|
|
104
|
+
klass = constant("#{namespace}::#{name}")
|
|
105
|
+
rescue
|
|
106
|
+
# drink it!
|
|
107
|
+
end
|
|
108
|
+
end unless klass
|
|
109
|
+
|
|
110
|
+
# Try to use Nitro::Element::xxx then ::xxx
|
|
111
|
+
|
|
112
|
+
begin
|
|
113
|
+
klass = constant("Nitro::Element::#{name}")
|
|
114
|
+
rescue
|
|
115
|
+
# drink it!
|
|
116
|
+
end unless klass
|
|
117
|
+
|
|
118
|
+
return false unless klass.kind_of? Class
|
|
119
|
+
|
|
120
|
+
# Try to auto-extend.
|
|
121
|
+
|
|
122
|
+
unless klass.ancestor? Element
|
|
123
|
+
if Element.auto_extend
|
|
124
|
+
klass.send(:include, ElementMixin)
|
|
125
|
+
else
|
|
126
|
+
return false
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
return klass
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def text(str)
|
|
134
|
+
@buffer << str
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def instruction(name, attributes)
|
|
138
|
+
@buffer << "<?#{name}#{attributes}?>"
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def cdata(content)
|
|
142
|
+
@buffer << "<![CDATA[#{content}]]>"
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def comment(c)
|
|
146
|
+
unless Template.strip_xml_comments
|
|
147
|
+
@buffer << "<!--#{c}-->"
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def doctype(name, pub_sys, long_name, uri)
|
|
152
|
+
@buffer << "<!DOCTYPE #{name} #{pub_sys} #{long_name} #{uri}>\n"
|
|
153
|
+
end
|
|
154
|
+
end # Listener
|
|
155
|
+
|
|
156
|
+
# Apply the filter.
|
|
157
|
+
|
|
158
|
+
def apply(source)
|
|
159
|
+
listen = Listener.new
|
|
160
|
+
REXML::Document.parse_stream(source, listen)
|
|
161
|
+
return listen.buffer
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
require "facets/core/string/demodulize"
|
|
2
|
+
require "facets/core/string/capitalized"
|
|
3
|
+
require "facets/core/string/camelize"
|
|
4
|
+
require "facets/core/class/method_name"
|
|
5
|
+
require "facets/core/dir/self/recurse"
|
|
6
|
+
require "facets/more/settings"
|
|
7
|
+
|
|
8
|
+
module Raw
|
|
9
|
+
|
|
10
|
+
# A programmatically generated element. Elements are a form
|
|
11
|
+
# of macros to allow for cleaner templates. They are evaluated
|
|
12
|
+
# at compile time, so there is no performance hit when you use
|
|
13
|
+
# them (at the expense of slightly reduced functionality).
|
|
14
|
+
#
|
|
15
|
+
# Nitro provides an additional method of defining elements.
|
|
16
|
+
# Instead of creating a lot of small classes, you can put
|
|
17
|
+
# .htmlx templates in the Element template_root. These templates
|
|
18
|
+
# are automatically converted into Element classes.
|
|
19
|
+
#
|
|
20
|
+
# For extra safety, you are advised to place your classes in the
|
|
21
|
+
# Nitro::Element namespace. If your classes do not extend
|
|
22
|
+
# Nitro::Element, the Nitro::ElementMixin is automatically
|
|
23
|
+
# injected in the class.
|
|
24
|
+
#
|
|
25
|
+
# An element can have and access a hierarchy of sub-elements.
|
|
26
|
+
# use #{content :sub_element_name} to access the render output
|
|
27
|
+
# of the subelement. Additionaly you can access the whole
|
|
28
|
+
# subelement object: _children[:sub_element_name]
|
|
29
|
+
#
|
|
30
|
+
# === Design
|
|
31
|
+
#
|
|
32
|
+
# An underscore is used for the standard attibutes to avoid name
|
|
33
|
+
# clashes.
|
|
34
|
+
|
|
35
|
+
module ElementMixin
|
|
36
|
+
# The parent of this element.
|
|
37
|
+
|
|
38
|
+
attr_accessor :_parent
|
|
39
|
+
|
|
40
|
+
# The children of this element.
|
|
41
|
+
|
|
42
|
+
attr_accessor :_children
|
|
43
|
+
alias_method :children, :_children
|
|
44
|
+
|
|
45
|
+
# The text of this element.
|
|
46
|
+
|
|
47
|
+
attr_accessor :_text
|
|
48
|
+
|
|
49
|
+
# The view of this element.
|
|
50
|
+
|
|
51
|
+
attr_accessor :_view
|
|
52
|
+
|
|
53
|
+
# The id of this element.
|
|
54
|
+
|
|
55
|
+
attr_accessor :id
|
|
56
|
+
|
|
57
|
+
def initialize(*args)
|
|
58
|
+
@_children = {}
|
|
59
|
+
@_text = ''
|
|
60
|
+
@id = self.class.to_s.demodulize.underscore
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Prepend this code to the element content.
|
|
64
|
+
|
|
65
|
+
def open
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# If an optional name parameter is passed renders
|
|
69
|
+
# the content of the named child element.
|
|
70
|
+
#
|
|
71
|
+
# eg. #{content :child_element_id}
|
|
72
|
+
#
|
|
73
|
+
# === Example
|
|
74
|
+
#
|
|
75
|
+
# <Page>
|
|
76
|
+
# ..
|
|
77
|
+
#
|
|
78
|
+
# <Box id="hello">
|
|
79
|
+
# ..
|
|
80
|
+
# </Box>
|
|
81
|
+
#
|
|
82
|
+
# <Box id="world">
|
|
83
|
+
# ..
|
|
84
|
+
# </Box>
|
|
85
|
+
#
|
|
86
|
+
# <Sidebar>
|
|
87
|
+
# ..
|
|
88
|
+
# </Sidebar>
|
|
89
|
+
#
|
|
90
|
+
# ..
|
|
91
|
+
#
|
|
92
|
+
# </Page>
|
|
93
|
+
#
|
|
94
|
+
# Access children content from within the enclosing element
|
|
95
|
+
# (Page) like this:
|
|
96
|
+
#
|
|
97
|
+
# {content :hello}
|
|
98
|
+
# {content :world}
|
|
99
|
+
# {content :sidebar}
|
|
100
|
+
|
|
101
|
+
def content(cname = nil)
|
|
102
|
+
if cname
|
|
103
|
+
if c = @_children[cname.to_s]
|
|
104
|
+
c.content
|
|
105
|
+
else
|
|
106
|
+
return nil
|
|
107
|
+
end
|
|
108
|
+
else
|
|
109
|
+
@_text
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# Include a text file in the element template. All the
|
|
114
|
+
# conventions of the StaticInclude compiler apply here. Please
|
|
115
|
+
# not that unless you pass an absolute path (starting with
|
|
116
|
+
# '/') you have to pass a controller instance as well.
|
|
117
|
+
#
|
|
118
|
+
# === Example:
|
|
119
|
+
#
|
|
120
|
+
# def render
|
|
121
|
+
# %~
|
|
122
|
+
# <div>
|
|
123
|
+
# #{include '/links/latest'}
|
|
124
|
+
# </div>
|
|
125
|
+
# ~
|
|
126
|
+
# end
|
|
127
|
+
|
|
128
|
+
def include(href, controller = nil)
|
|
129
|
+
filename = StaticIncludeFilter.new.resolve_include_filename(href)
|
|
130
|
+
return File.read(filename)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Append this code to the element content.
|
|
134
|
+
|
|
135
|
+
def close
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Override this.
|
|
139
|
+
|
|
140
|
+
def render
|
|
141
|
+
"#{open}#{content}#{close}"
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def render_children
|
|
145
|
+
str = ''
|
|
146
|
+
for c in @_children.values
|
|
147
|
+
str << c.render
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
return str
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def add_child(child)
|
|
154
|
+
child._parent = self
|
|
155
|
+
@_children[child.instance_variable_get('@id')] = child
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
alias_method :children, :_children
|
|
159
|
+
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
# A programmatically generated element.
|
|
163
|
+
#
|
|
164
|
+
# === Usage
|
|
165
|
+
#
|
|
166
|
+
# = in the code
|
|
167
|
+
#
|
|
168
|
+
# class Page < Nitro::Element
|
|
169
|
+
# def render
|
|
170
|
+
# %{
|
|
171
|
+
# <div id="@id">#{content}</div>
|
|
172
|
+
# }
|
|
173
|
+
# end
|
|
174
|
+
# end
|
|
175
|
+
#
|
|
176
|
+
# = in your template
|
|
177
|
+
#
|
|
178
|
+
# <Page>hello</Page>
|
|
179
|
+
#
|
|
180
|
+
# => <div id="page">hello</div>
|
|
181
|
+
#
|
|
182
|
+
# the id is automatically fille with the class name using
|
|
183
|
+
# class.method_name eg. MyModule::MyPage => my_module__my_page
|
|
184
|
+
#
|
|
185
|
+
# you can override the id to use the element multiple times on
|
|
186
|
+
# the page.
|
|
187
|
+
#
|
|
188
|
+
# == Sub Elements
|
|
189
|
+
#
|
|
190
|
+
# Elements can be imbricated. To render the the child element in
|
|
191
|
+
# the parent's template, use #{content :element_id}
|
|
192
|
+
#
|
|
193
|
+
# === Design
|
|
194
|
+
#
|
|
195
|
+
# An underscore is used for the standard attibutes to avoid name
|
|
196
|
+
# clashes.
|
|
197
|
+
|
|
198
|
+
class Element
|
|
199
|
+
include ElementMixin
|
|
200
|
+
|
|
201
|
+
# The prefix for element tags (in xhtml compatibility mode)
|
|
202
|
+
|
|
203
|
+
setting :prefix, :default => 'x', :doc => 'The prefix for element tags'
|
|
204
|
+
|
|
205
|
+
# Allow auto extension of element classes?
|
|
206
|
+
|
|
207
|
+
setting :auto_extend, :default => true, :doc => 'Allow auto extension of element classes?'
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end
|