raw 0.49.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/doc/CONTRIBUTORS +106 -0
  2. data/doc/LICENSE +32 -0
  3. data/doc/coding_conventions.txt +11 -0
  4. data/lib/raw.rb +42 -0
  5. data/lib/raw/adapter.rb +113 -0
  6. data/lib/raw/adapter/cgi.rb +41 -0
  7. data/lib/raw/adapter/fastcgi.rb +48 -0
  8. data/lib/raw/adapter/mongrel.rb +146 -0
  9. data/lib/raw/adapter/script.rb +94 -0
  10. data/lib/raw/adapter/webrick.rb +144 -0
  11. data/lib/raw/adapter/webrick/vcr.rb +91 -0
  12. data/lib/raw/cgi.rb +323 -0
  13. data/lib/raw/cgi/cookie.rb +47 -0
  14. data/lib/raw/cgi/http.rb +62 -0
  15. data/lib/raw/compiler.rb +138 -0
  16. data/lib/raw/compiler/filter/cleanup.rb +21 -0
  17. data/lib/raw/compiler/filter/elements.rb +166 -0
  18. data/lib/raw/compiler/filter/elements/element.rb +210 -0
  19. data/lib/raw/compiler/filter/localization.rb +23 -0
  20. data/lib/raw/compiler/filter/markup.rb +32 -0
  21. data/lib/raw/compiler/filter/morph.rb +123 -0
  22. data/lib/raw/compiler/filter/morph/each.rb +34 -0
  23. data/lib/raw/compiler/filter/morph/for.rb +11 -0
  24. data/lib/raw/compiler/filter/morph/if.rb +26 -0
  25. data/lib/raw/compiler/filter/morph/selected_if.rb +43 -0
  26. data/lib/raw/compiler/filter/morph/standard.rb +55 -0
  27. data/lib/raw/compiler/filter/morph/times.rb +27 -0
  28. data/lib/raw/compiler/filter/script.rb +116 -0
  29. data/lib/raw/compiler/filter/squeeze.rb +16 -0
  30. data/lib/raw/compiler/filter/static_include.rb +74 -0
  31. data/lib/raw/compiler/filter/template.rb +121 -0
  32. data/lib/raw/compiler/reloader.rb +96 -0
  33. data/lib/raw/context.rb +154 -0
  34. data/lib/raw/context/flash.rb +157 -0
  35. data/lib/raw/context/global.rb +88 -0
  36. data/lib/raw/context/request.rb +338 -0
  37. data/lib/raw/context/response.rb +57 -0
  38. data/lib/raw/context/session.rb +198 -0
  39. data/lib/raw/context/session/drb.rb +11 -0
  40. data/lib/raw/context/session/file.rb +15 -0
  41. data/lib/raw/context/session/memcached.rb +13 -0
  42. data/lib/raw/context/session/memory.rb +12 -0
  43. data/lib/raw/context/session/og.rb +15 -0
  44. data/lib/raw/context/session/pstore.rb +13 -0
  45. data/lib/raw/control.rb +18 -0
  46. data/lib/raw/control/attribute.rb +91 -0
  47. data/lib/raw/control/attribute/checkbox.rb +25 -0
  48. data/lib/raw/control/attribute/datetime.rb +21 -0
  49. data/lib/raw/control/attribute/file.rb +20 -0
  50. data/lib/raw/control/attribute/fixnum.rb +26 -0
  51. data/lib/raw/control/attribute/float.rb +26 -0
  52. data/lib/raw/control/attribute/options.rb +38 -0
  53. data/lib/raw/control/attribute/password.rb +16 -0
  54. data/lib/raw/control/attribute/text.rb +16 -0
  55. data/lib/raw/control/attribute/textarea.rb +16 -0
  56. data/lib/raw/control/none.rb +16 -0
  57. data/lib/raw/control/relation.rb +59 -0
  58. data/lib/raw/control/relation/belongs_to.rb +0 -0
  59. data/lib/raw/control/relation/has_many.rb +97 -0
  60. data/lib/raw/control/relation/joins_many.rb +0 -0
  61. data/lib/raw/control/relation/many_to_many.rb +0 -0
  62. data/lib/raw/control/relation/refers_to.rb +29 -0
  63. data/lib/raw/controller.rb +37 -0
  64. data/lib/raw/controller/publishable.rb +160 -0
  65. data/lib/raw/dispatcher.rb +209 -0
  66. data/lib/raw/dispatcher/format.rb +108 -0
  67. data/lib/raw/dispatcher/format/atom.rb +31 -0
  68. data/lib/raw/dispatcher/format/css.rb +0 -0
  69. data/lib/raw/dispatcher/format/html.rb +42 -0
  70. data/lib/raw/dispatcher/format/json.rb +31 -0
  71. data/lib/raw/dispatcher/format/rss.rb +33 -0
  72. data/lib/raw/dispatcher/format/xoxo.rb +31 -0
  73. data/lib/raw/dispatcher/mounter.rb +60 -0
  74. data/lib/raw/dispatcher/router.rb +111 -0
  75. data/lib/raw/errors.rb +19 -0
  76. data/lib/raw/helper.rb +86 -0
  77. data/lib/raw/helper/benchmark.rb +23 -0
  78. data/lib/raw/helper/buffer.rb +60 -0
  79. data/lib/raw/helper/cookie.rb +32 -0
  80. data/lib/raw/helper/debug.rb +28 -0
  81. data/lib/raw/helper/default.rb +16 -0
  82. data/lib/raw/helper/feed.rb +451 -0
  83. data/lib/raw/helper/form.rb +284 -0
  84. data/lib/raw/helper/javascript.rb +59 -0
  85. data/lib/raw/helper/layout.rb +40 -0
  86. data/lib/raw/helper/navigation.rb +87 -0
  87. data/lib/raw/helper/pager.rb +305 -0
  88. data/lib/raw/helper/table.rb +247 -0
  89. data/lib/raw/helper/xhtml.rb +218 -0
  90. data/lib/raw/helper/xml.rb +125 -0
  91. data/lib/raw/mixin/magick.rb +35 -0
  92. data/lib/raw/mixin/sweeper.rb +71 -0
  93. data/lib/raw/mixin/thumbnails.rb +1 -0
  94. data/lib/raw/mixin/webfile.rb +165 -0
  95. data/lib/raw/render.rb +271 -0
  96. data/lib/raw/render/builder.rb +26 -0
  97. data/lib/raw/render/caching.rb +81 -0
  98. data/lib/raw/render/call.rb +43 -0
  99. data/lib/raw/render/send_file.rb +46 -0
  100. data/lib/raw/render/stream.rb +39 -0
  101. data/lib/raw/scaffold.rb +13 -0
  102. data/lib/raw/scaffold/controller.rb +25 -0
  103. data/lib/raw/scaffold/model.rb +157 -0
  104. data/lib/raw/test.rb +5 -0
  105. data/lib/raw/test/assertions.rb +169 -0
  106. data/lib/raw/test/context.rb +55 -0
  107. data/lib/raw/test/testcase.rb +79 -0
  108. data/lib/raw/util/attr.rb +128 -0
  109. data/lib/raw/util/encode_uri.rb +149 -0
  110. data/lib/raw/util/html_filter.rb +538 -0
  111. data/lib/raw/util/markup.rb +130 -0
  112. data/test/glue/tc_webfile.rb +1 -0
  113. data/test/nitro/CONFIG.rb +3 -0
  114. data/test/nitro/adapter/raw_post1.bin +9 -0
  115. data/test/nitro/adapter/tc_webrick.rb +16 -0
  116. data/test/nitro/cgi/tc_cookie.rb +14 -0
  117. data/test/nitro/cgi/tc_request.rb +61 -0
  118. data/test/nitro/compiler/tc_client_morpher.rb +47 -0
  119. data/test/nitro/compiler/tc_compiler.rb +25 -0
  120. data/test/nitro/dispatcher/tc_mounter.rb +47 -0
  121. data/test/nitro/helper/tc_feed.rb +135 -0
  122. data/test/nitro/helper/tc_navbar.rb +74 -0
  123. data/test/nitro/helper/tc_pager.rb +35 -0
  124. data/test/nitro/helper/tc_table.rb +68 -0
  125. data/test/nitro/helper/tc_xhtml.rb +19 -0
  126. data/test/nitro/tc_caching.rb +19 -0
  127. data/test/nitro/tc_cgi.rb +222 -0
  128. data/test/nitro/tc_context.rb +17 -0
  129. data/test/nitro/tc_controller.rb +103 -0
  130. data/test/nitro/tc_controller_aspect.rb +32 -0
  131. data/test/nitro/tc_controller_params.rb +885 -0
  132. data/test/nitro/tc_dispatcher.rb +109 -0
  133. data/test/nitro/tc_element.rb +85 -0
  134. data/test/nitro/tc_flash.rb +59 -0
  135. data/test/nitro/tc_helper.rb +47 -0
  136. data/test/nitro/tc_render.rb +119 -0
  137. data/test/nitro/tc_router.rb +61 -0
  138. data/test/nitro/tc_server.rb +35 -0
  139. data/test/nitro/tc_session.rb +66 -0
  140. data/test/nitro/tc_template.rb +71 -0
  141. data/test/nitro/util/tc_encode_url.rb +87 -0
  142. data/test/nitro/util/tc_markup.rb +31 -0
  143. data/test/public/blog/another/very_litle/index.xhtml +1 -0
  144. data/test/public/blog/inc1.xhtml +2 -0
  145. data/test/public/blog/inc2.xhtml +1 -0
  146. data/test/public/blog/list.xhtml +9 -0
  147. data/test/public/dummy_mailer/registration.xhtml +5 -0
  148. 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
@@ -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
@@ -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