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,160 @@
1
+ require "facets/more/ann"
2
+
3
+ require "raw/render"
4
+ require "raw/render/caching"
5
+ require "raw/context/flash"
6
+ require "raw/helper"
7
+ require "raw/helper/cookie"
8
+ require "raw/compiler"
9
+ require "raw/compiler/filter/template"
10
+ require "raw/util/encode_uri"
11
+ require "raw/util/markup"
12
+
13
+ module Raw
14
+
15
+ # Include this Mixin to a class to make objects of this class
16
+ # publishable, ie accessible through a standard web (REST)
17
+ # interface.
18
+
19
+ module Publishable
20
+ def self.included(base)
21
+ super
22
+ base.send(:include, Render)
23
+ base.send(:include, Flashing)
24
+ base.send(:include, Caching)
25
+ base.send(:include, Helpers)
26
+ base.helper(EncodeURI)
27
+ base.helper(CookieHelper)
28
+ base.helper(Markup)
29
+ end
30
+
31
+ # Use the method_missing hook to compile the actions
32
+ # for this controller.
33
+
34
+ def method_missing(action, *args)
35
+ if Context.current.application.compiler.compile(self.class, action)
36
+ send(action, *args)
37
+ else
38
+ super
39
+ end
40
+ end
41
+
42
+ class_extension do
43
+
44
+ # The path where this controller is mounted.
45
+
46
+ attr_accessor :mount_path
47
+
48
+ # Return the 'action' methods for this Object. Some
49
+ # dangerous methods from ancestors are removed. All private
50
+ # methods are ignored.
51
+ #--
52
+ # gmosx, TODO: We should optimize this method.
53
+ #++
54
+
55
+ def action_methods
56
+ public_instance_methods - Controller.public_instance_methods
57
+ end
58
+ alias_method :actions, :action_methods
59
+
60
+ # Check if the controller responds to this action.
61
+
62
+ def action?(action)
63
+ action_methods.include?(action.to_s)
64
+ end
65
+ alias_method :respond_to_action?, :action?
66
+
67
+ # Check if the a template for this action and format exists.
68
+ # Returns a valid path or nil.
69
+
70
+ def template?(action, format)
71
+ # Allow for template override using the :template annotation
72
+ #
73
+ # class MyController
74
+ # def myaction
75
+ # end
76
+ # ann :myaction, :template => :another_template
77
+ # end
78
+
79
+ template = ann(action, :template) || action
80
+
81
+ template = template.to_s.gsub(/__/, "/")
82
+
83
+ for dir in ann(:self, :template_dir_stack)
84
+ name = "#{dir}/#{template}".squeeze("/")
85
+
86
+ # attempt to find a template of the form:
87
+ # dir/action.xhtml
88
+
89
+ path = "#{name}.#{format.template_extension}"
90
+ return path if File.exist?(path)
91
+
92
+ # attempt to find a template of the form:
93
+ # dir/action/index.xhtml
94
+
95
+ path = "#{name}/index.#{format.template_extension}"
96
+ return path if File.exist?(path)
97
+ end
98
+
99
+ return nil
100
+ end
101
+ alias_method :has_template?, :template?
102
+ alias_method :template_path, :template?
103
+
104
+ # Check if this action or template exists.
105
+
106
+ def action_or_template?(action, format)
107
+ action?(action) or template?(action, format)
108
+ end
109
+ alias_method :respond_to_action_or_template?, :action_or_template?
110
+
111
+ # Aliases an action
112
+ #--
113
+ # gmosx, FIXME: better implementation needed.
114
+ # gmosx, FIXME: copy all annotations.
115
+ #++
116
+
117
+ def alias_action(new, old)
118
+ alias_method new, old
119
+ ann new, :template => old
120
+ end
121
+
122
+ # Override this method to customize the template_dir_stack.
123
+ # Typically used in controllers defined in reusable Parts.
124
+ # Call super to include the parent class's customizations.
125
+ # Implements some form of template root inheritance,
126
+ # thus allowing for more reusable controllers. Ie you can
127
+ # 'extend' a controller, and only override the templates
128
+ # you want to change. The compiler will traverse the
129
+ # template dir stack and use the templates from parent
130
+ # controllers if they are not overriden.
131
+ #
132
+ # def self.setup_template_dir_stack(stack)
133
+ # super
134
+ # stack << "custom/route/#{self.mount_path}"
135
+ # stack << "another/route"
136
+ # end
137
+
138
+ def setup_template_dir_stack(path)
139
+ end
140
+
141
+ # This callback is called when this controller is mounted.
142
+
143
+ def mount_at(path)
144
+ @mount_path = path
145
+
146
+ # Setup the template_dir_stack.
147
+
148
+ stack = []
149
+ stack << File.join(Template.root_dir, path).gsub(/\/$/, "")
150
+ self.setup_template_dir_stack(stack)
151
+ stack << File.join(Nitro.proto_path, "template", path).gsub(/\/$/, "")
152
+ ann(:self, :template_dir_stack => stack)
153
+ end
154
+ alias_method :mount, :mount_at
155
+
156
+ end # class_extension
157
+
158
+ end
159
+
160
+ end
@@ -0,0 +1,209 @@
1
+ require "facets/core/module/ancestor"
2
+
3
+ require "raw/dispatcher/router"
4
+ require "raw/dispatcher/mounter"
5
+ require "raw/dispatcher/format"
6
+
7
+ module Raw
8
+
9
+ # The Dispatcher manages a set of controllers. It selects the
10
+ # appropriate Controller and action to handle the given
11
+ # request.
12
+ #
13
+ # This dispatcher intelligently handles RESTful uris according
14
+ # to the following scheme:
15
+ #
16
+ # GET /links GET /links/index Link::Controller#index
17
+ # POST /links POST /links/create Link::Controller#create
18
+ # GET /links;new GET /links/new Link::Controller#new
19
+ # GET /links/1 Link::Controller#view(1)
20
+ # GET /links/1;edit GET /links/edit/1 Link::Controller#edit(1)
21
+ # PUT /links/1 POST /links/update/1 Link::Controller#update
22
+ # DELETE /links/1 GET /links/delete/1 Link::Controller#delete(1)
23
+ # GET /links/index.xml Link::Controller#index # Atom
24
+ # GET /links/index.json Link::Controller#index # JSON
25
+ #
26
+ # The default actions for the various methods are:
27
+ #
28
+ # GET: index
29
+ # POST: create
30
+ # PUT: update
31
+ # DELETE: delete
32
+
33
+ class Dispatcher
34
+
35
+ # The (optional) router.
36
+
37
+ attr_accessor :router
38
+
39
+ # The hash that maps mount paths to controllers.
40
+
41
+ attr_accessor :controllers
42
+
43
+ # The representation formats this dispatcher understands.
44
+
45
+ attr_accessor :formats
46
+
47
+ # Initialize the dispatcher.
48
+
49
+ def initialize(controller_or_map = nil)
50
+ @controllers = {}
51
+ @formats = Nitro::STANDARD_FORMATS.dup
52
+
53
+ if controller_or_map.is_a?(Class)
54
+ mount("/" => controller_or_map)
55
+ elsif controller_or_map.is_a?(Hash)
56
+ mount(controller_or_map)
57
+ end
58
+ end
59
+
60
+ # Mounts a map of controllers.
61
+
62
+ def mount(map)
63
+ for path, controller in map
64
+ self[path] = controller
65
+ end
66
+ end
67
+
68
+ # Return the controller for the given mount path.
69
+
70
+ def [](path = "/")
71
+ @controllers[path]
72
+ end
73
+
74
+ # Mount a controller to the given mount path.
75
+
76
+ def []=(path, controller)
77
+ controller = resolve_controller(controller)
78
+
79
+ # Customize the class for mounting at the given path.
80
+ controller.mount_at(path) if controller.respond_to? :mount_at
81
+
82
+ # Call the mounted callback to allow for post mount
83
+ # initialization.
84
+ controller.mounted(path) if controller.respond_to? :mounted
85
+
86
+ @controllers[path] = controller
87
+ end
88
+
89
+ # Dispatch a request. Calls the lower level dispatch method.
90
+
91
+ def dispatch_request(request)
92
+ dispatch(request.uri, request.method)
93
+ end
94
+ alias_method :dispatch_context, :dispatch_request
95
+
96
+ # Dispatch a path given the request method. This method
97
+ # handles fully resolved paths (containing an extension that
98
+ # denotes the expected content type).
99
+ #
100
+ # This method automatically handles 'nice' (seo friendly, elegant)
101
+ # parameters, ie:
102
+ #
103
+ # /links/view/1
104
+ #
105
+ # instead of
106
+ #
107
+ # /links/view?oid=1
108
+ #
109
+ # === Output
110
+ #
111
+ # controller, action, query_string, nice_params, extension
112
+ #
113
+ #--
114
+ # Lower level, useful for testing.
115
+ #++
116
+
117
+ def dispatch(uri, method = :get)
118
+ # Extract the query string.
119
+
120
+ path, query = uri.split("?", 2)
121
+
122
+ # Try to route the path.
123
+
124
+ path = @router.route(path) if @router
125
+
126
+ # The characters after the last '.' in the path form the
127
+ # extension that itself represents the expected response
128
+ # content type.
129
+
130
+ ext = File.extname(path)[1..-1] || "html"
131
+
132
+ # The resource representation format for this request.
133
+
134
+ unless format = Context.current.format = @formats.by_extension[ext]
135
+ raise ActionError.new("Cannot respond to '#{path}' using the '#{ext}' format representation.")
136
+ end
137
+
138
+ # Remove the extension from the path.
139
+
140
+ path = path.gsub(/\.(.*)$/, '')
141
+
142
+ # Try to extract the controller from the path (that may also
143
+ # include 'nice' parameters). This algorithm tries to find
144
+ # the bigest substring of the path that represents a mount
145
+ # path for a controller.
146
+
147
+ key = path.dup
148
+
149
+ while (controller = @controllers[key]).nil?
150
+ key = key[%r{^(/.+)/.+$}, 1] || '/'
151
+ end
152
+
153
+ # Try to extract the controller from the path. This
154
+ # algorithm tries to find the bigest substring of the path
155
+ # that represents an action of this controller.
156
+ #
157
+ # The algorithm respects action name conventions, ie
158
+ # simple/sub/action maps to simple__sub__action.
159
+
160
+ action = key = path.sub(%r{^#{key}}, '').gsub(%r{^/}, '').gsub(%r{/}, '__')
161
+
162
+ while (!action.blank?) and !controller.action_or_template?(action, format)
163
+ action = action[%r{^(.+)__.+$}, 1]
164
+ end
165
+
166
+ # Extract the 'nice' parameters.
167
+
168
+ params = key.sub(%r{^#{action}}, '').gsub(/^__/, '').split('__')
169
+
170
+ # Do we have an action?
171
+
172
+ if action.blank?
173
+ # Try to use a standard action for this http method.
174
+
175
+ case method
176
+ when :get
177
+ action = "index"
178
+
179
+ when :post
180
+ action = "create"
181
+
182
+ when :delete
183
+ action = "delete"
184
+
185
+ when :put
186
+ action = "update"
187
+ end
188
+
189
+ unless controller.action_or_template?(action, format)
190
+ raise ActionError.new("Cannot respond to '#{path}' using '#{controller}'")
191
+ end
192
+ end
193
+
194
+ return controller, "#{action}___super", query, params, ext
195
+ end
196
+
197
+ private
198
+
199
+ def resolve_controller(controller)
200
+ unless controller.ancestor?(Controller) or controller.ancestor?(Publishable)
201
+ controller.send(:include, Publishable)
202
+ end
203
+
204
+ return controller
205
+ end
206
+
207
+ end
208
+
209
+ end
@@ -0,0 +1,108 @@
1
+ module Raw
2
+
3
+ # A REST Resource Representation format.
4
+
5
+ class Format
6
+
7
+ # The name of this format.
8
+
9
+ attr_accessor :name
10
+
11
+ # The resource content type. Typically the resource MIME type
12
+ # is used.
13
+
14
+ attr_accessor :content_type
15
+ alias_method :mime_type, :content_type
16
+
17
+ # The default resource extension.
18
+
19
+ attr_accessor :extension
20
+
21
+ # The default template extension.
22
+
23
+ attr_accessor :template_extension
24
+
25
+ def to_s
26
+ @name
27
+ end
28
+
29
+ # Apply filters to the template source. The original template
30
+ # representation must be transformed to executable Ruby code
31
+ # at the end.
32
+
33
+ def filter_template(source)
34
+ return source
35
+ end
36
+
37
+ # This callback is called before the action is executed with
38
+ # this format.
39
+
40
+ def before_action(controller, context)
41
+ end
42
+
43
+ # This callback is called after the action is executed with
44
+ # this format.
45
+
46
+ def after_action(controller, context)
47
+ end
48
+
49
+ end
50
+
51
+ # A Format Manager. Provides useful methods for fast Format
52
+ # lookup.
53
+
54
+ class FormatManager
55
+ # Formats indexed by name.
56
+
57
+ attr_accessor :by_name
58
+
59
+ # Formats indexed by mime type.
60
+
61
+ attr_accessor :by_mime_type
62
+
63
+ # Formats indexed by extension.
64
+
65
+ attr_accessor :by_extension
66
+
67
+ def initialize(*formats)
68
+ @by_name = {}
69
+ @by_mime_type = {}
70
+ @by_extension = {}
71
+
72
+ for format in formats.flatten
73
+ put(format)
74
+ end
75
+ end
76
+
77
+ # Add a new format to the manager.
78
+
79
+ def put(format)
80
+ if format.is_a? Class
81
+ format = format.new
82
+ end
83
+
84
+ @by_name[format.name] = format
85
+ @by_mime_type[format.mime_type] = format
86
+ @by_extension[format.extension] = format
87
+ end
88
+ alias_method :<<, :put
89
+
90
+ # Lookup a format by name.
91
+
92
+ def [](name)
93
+ @by_name[name]
94
+ end
95
+
96
+ end
97
+
98
+ require "raw/dispatcher/format/html"
99
+ require "raw/dispatcher/format/atom"
100
+ require "raw/dispatcher/format/rss"
101
+ require "raw/dispatcher/format/json"
102
+ require "raw/dispatcher/format/xoxo"
103
+
104
+ STANDARD_FORMATS = FormatManager.new(
105
+ HTMLFormat, ATOMFormat, RSSFormat, JSONFormat, XOXOFormat
106
+ )
107
+
108
+ end