waves-stable 0.7.7

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.
Files changed (185) hide show
  1. data/app/Rakefile +72 -0
  2. data/app/bin/waves-console +4 -0
  3. data/app/bin/waves-server +4 -0
  4. data/app/configurations/development.rb.erb +31 -0
  5. data/app/configurations/mapping.rb.erb +14 -0
  6. data/app/configurations/production.rb.erb +31 -0
  7. data/app/controllers/.gitignore +0 -0
  8. data/app/doc/.gitignore +0 -0
  9. data/app/helpers/.gitignore +0 -0
  10. data/app/lib/application.rb.erb +5 -0
  11. data/app/lib/tasks/.gitignore +0 -0
  12. data/app/log/.gitignore +0 -0
  13. data/app/models/.gitignore +0 -0
  14. data/app/public/css/.gitignore +0 -0
  15. data/app/public/flash/.gitignore +0 -0
  16. data/app/public/images/.gitignore +0 -0
  17. data/app/public/javascript/.gitignore +0 -0
  18. data/app/schema/migrations/.gitignore +0 -0
  19. data/app/startup.rb +5 -0
  20. data/app/templates/errors/not_found_404.mab +2 -0
  21. data/app/templates/errors/server_error_500.mab +2 -0
  22. data/app/templates/layouts/default.mab +14 -0
  23. data/app/tmp/sessions/.gitignore +0 -0
  24. data/app/views/.gitignore +0 -0
  25. data/bin/waves +84 -0
  26. data/bin/waves-console +4 -0
  27. data/bin/waves-server +4 -0
  28. data/doc/HISTORY +44 -0
  29. data/doc/LICENSE +22 -0
  30. data/lib/commands/waves-console.rb +21 -0
  31. data/lib/commands/waves-server.rb +55 -0
  32. data/lib/controllers/base.rb +11 -0
  33. data/lib/controllers/mixin.rb +165 -0
  34. data/lib/dispatchers/base.rb +67 -0
  35. data/lib/dispatchers/default.rb +81 -0
  36. data/lib/foundations/default.rb +27 -0
  37. data/lib/foundations/simple.rb +30 -0
  38. data/lib/helpers/asset_helper.rb +67 -0
  39. data/lib/helpers/common.rb +66 -0
  40. data/lib/helpers/default.rb +13 -0
  41. data/lib/helpers/form.rb +40 -0
  42. data/lib/helpers/formatting.rb +30 -0
  43. data/lib/helpers/model.rb +33 -0
  44. data/lib/helpers/number_helper.rb +25 -0
  45. data/lib/helpers/tag_helper.rb +58 -0
  46. data/lib/helpers/url_helper.rb +77 -0
  47. data/lib/helpers/view.rb +24 -0
  48. data/lib/layers/default_errors.rb +26 -0
  49. data/lib/layers/inflect/english.rb +24 -0
  50. data/lib/layers/inflect/english/rules.rb +88 -0
  51. data/lib/layers/inflect/english/string.rb +24 -0
  52. data/lib/layers/mvc.rb +54 -0
  53. data/lib/layers/orm/active_record.rb +92 -0
  54. data/lib/layers/orm/active_record/migrations/empty.rb.erb +9 -0
  55. data/lib/layers/orm/active_record/tasks/generate.rb +28 -0
  56. data/lib/layers/orm/active_record/tasks/schema.rb +22 -0
  57. data/lib/layers/orm/data_mapper.rb +38 -0
  58. data/lib/layers/orm/filebase.rb +22 -0
  59. data/lib/layers/orm/migration.rb +79 -0
  60. data/lib/layers/orm/sequel.rb +86 -0
  61. data/lib/layers/orm/sequel/migrations/empty.rb.erb +9 -0
  62. data/lib/layers/orm/sequel/tasks/generate.rb +28 -0
  63. data/lib/layers/orm/sequel/tasks/schema.rb +16 -0
  64. data/lib/layers/simple.rb +32 -0
  65. data/lib/layers/simple_errors.rb +23 -0
  66. data/lib/mapping/mapping.rb +289 -0
  67. data/lib/mapping/pretty_urls.rb +96 -0
  68. data/lib/renderers/erubis.rb +63 -0
  69. data/lib/renderers/haml.rb +45 -0
  70. data/lib/renderers/markaby.rb +33 -0
  71. data/lib/renderers/mixin.rb +50 -0
  72. data/lib/runtime/application.rb +69 -0
  73. data/lib/runtime/blackboard.rb +57 -0
  74. data/lib/runtime/configuration.rb +185 -0
  75. data/lib/runtime/console.rb +20 -0
  76. data/lib/runtime/debugger.rb +9 -0
  77. data/lib/runtime/logger.rb +59 -0
  78. data/lib/runtime/mime_types.rb +22 -0
  79. data/lib/runtime/request.rb +78 -0
  80. data/lib/runtime/response.rb +40 -0
  81. data/lib/runtime/response_mixin.rb +38 -0
  82. data/lib/runtime/response_proxy.rb +30 -0
  83. data/lib/runtime/server.rb +107 -0
  84. data/lib/runtime/session.rb +66 -0
  85. data/lib/tasks/cluster.rb +26 -0
  86. data/lib/tasks/gem.rb +31 -0
  87. data/lib/tasks/generate.rb +80 -0
  88. data/lib/utilities/hash.rb +31 -0
  89. data/lib/utilities/inflect.rb +110 -0
  90. data/lib/utilities/integer.rb +24 -0
  91. data/lib/utilities/module.rb +21 -0
  92. data/lib/utilities/object.rb +25 -0
  93. data/lib/utilities/proc.rb +16 -0
  94. data/lib/utilities/string.rb +49 -0
  95. data/lib/utilities/symbol.rb +10 -0
  96. data/lib/utilities/tempfile.rb +9 -0
  97. data/lib/views/base.rb +9 -0
  98. data/lib/views/mixin.rb +110 -0
  99. data/lib/waves.rb +84 -0
  100. data/samples/blog/Rakefile +14 -0
  101. data/samples/blog/bin/waves-console +3 -0
  102. data/samples/blog/bin/waves-server +3 -0
  103. data/samples/blog/configurations/development.rb +31 -0
  104. data/samples/blog/configurations/mapping.rb +23 -0
  105. data/samples/blog/configurations/production.rb +30 -0
  106. data/samples/blog/doc/EMTPY +0 -0
  107. data/samples/blog/lib/application.rb +5 -0
  108. data/samples/blog/models/comment.rb +14 -0
  109. data/samples/blog/models/entry.rb +14 -0
  110. data/samples/blog/public/css/site.css +2 -0
  111. data/samples/blog/public/javascript/site.js +13 -0
  112. data/samples/blog/schema/migrations/001_initial_schema.rb +17 -0
  113. data/samples/blog/schema/migrations/002_add_comments.rb +18 -0
  114. data/samples/blog/schema/migrations/templates/empty.rb.erb +9 -0
  115. data/samples/blog/startup.rb +6 -0
  116. data/samples/blog/templates/comment/add.mab +10 -0
  117. data/samples/blog/templates/comment/list.mab +6 -0
  118. data/samples/blog/templates/entry/editor.mab +13 -0
  119. data/samples/blog/templates/entry/list.mab +11 -0
  120. data/samples/blog/templates/entry/show.mab +9 -0
  121. data/samples/blog/templates/entry/summary.mab +5 -0
  122. data/samples/blog/templates/errors/not_found_404.mab +2 -0
  123. data/samples/blog/templates/errors/server_error_500.mab +2 -0
  124. data/samples/blog/templates/layouts/default.mab +17 -0
  125. data/verify/app_generation/helpers.rb +24 -0
  126. data/verify/app_generation/startup.rb +39 -0
  127. data/verify/blackboard/blackboard_verify.rb +92 -0
  128. data/verify/blackboard/helpers.rb +5 -0
  129. data/verify/configurations/attributes.rb +37 -0
  130. data/verify/configurations/helpers.rb +1 -0
  131. data/verify/configurations/rack_integration.rb +29 -0
  132. data/verify/controllers/base.rb +37 -0
  133. data/verify/controllers/helpers.rb +13 -0
  134. data/verify/controllers/interface.rb +51 -0
  135. data/verify/core/helpers.rb +3 -0
  136. data/verify/core/utilities.rb +177 -0
  137. data/verify/foundations/default.rb +86 -0
  138. data/verify/foundations/default_application/Rakefile +14 -0
  139. data/verify/foundations/default_application/bin/waves-console +3 -0
  140. data/verify/foundations/default_application/bin/waves-server +3 -0
  141. data/verify/foundations/default_application/configurations/development.rb +26 -0
  142. data/verify/foundations/default_application/configurations/mapping.rb +14 -0
  143. data/verify/foundations/default_application/configurations/production.rb +30 -0
  144. data/verify/foundations/default_application/controllers/default.rb +15 -0
  145. data/verify/foundations/default_application/controllers/loaded.rb +15 -0
  146. data/verify/foundations/default_application/defaultapplication.db +0 -0
  147. data/verify/foundations/default_application/helpers/loaded.rb +10 -0
  148. data/verify/foundations/default_application/lib/application.rb +5 -0
  149. data/verify/foundations/default_application/models/default.rb +13 -0
  150. data/verify/foundations/default_application/models/loaded.rb +13 -0
  151. data/verify/foundations/default_application/schema/migrations/templates/empty.rb.erb +9 -0
  152. data/verify/foundations/default_application/startup.rb +7 -0
  153. data/verify/foundations/default_application/templates/errors/not_found_404.mab +2 -0
  154. data/verify/foundations/default_application/templates/errors/server_error_500.mab +2 -0
  155. data/verify/foundations/default_application/templates/layouts/default.mab +14 -0
  156. data/verify/foundations/default_application/views/default.rb +7 -0
  157. data/verify/foundations/default_application/views/loaded.rb +15 -0
  158. data/verify/foundations/helpers.rb +1 -0
  159. data/verify/foundations/simple.rb +25 -0
  160. data/verify/helpers.rb +76 -0
  161. data/verify/layers/data_mapper/association_verify.rb +87 -0
  162. data/verify/layers/default_errors.rb +29 -0
  163. data/verify/layers/helpers.rb +1 -0
  164. data/verify/layers/migration.rb +33 -0
  165. data/verify/layers/sequel/model.rb +41 -0
  166. data/verify/mapping/always.rb +19 -0
  167. data/verify/mapping/filters.rb +65 -0
  168. data/verify/mapping/handle.rb +24 -0
  169. data/verify/mapping/helpers.rb +7 -0
  170. data/verify/mapping/matches.rb +27 -0
  171. data/verify/mapping/named.rb +29 -0
  172. data/verify/mapping/options.rb +17 -0
  173. data/verify/mapping/path.rb +40 -0
  174. data/verify/mapping/response_proxy.rb +50 -0
  175. data/verify/mapping/threaded.rb +25 -0
  176. data/verify/requests/helpers.rb +16 -0
  177. data/verify/requests/request.rb +73 -0
  178. data/verify/requests/response.rb +59 -0
  179. data/verify/requests/session.rb +54 -0
  180. data/verify/views/helpers.rb +1 -0
  181. data/verify/views/rendering.rb +34 -0
  182. data/verify/views/templates/foo.erb +0 -0
  183. data/verify/views/templates/moo.erb +0 -0
  184. data/verify/views/templates/moo.mab +0 -0
  185. metadata +439 -0
@@ -0,0 +1,11 @@
1
+ module Waves
2
+ module Controllers
3
+ class Base
4
+
5
+ include Waves::Controllers::Mixin
6
+
7
+ def attributes; params[model_name.singular.intern]; end
8
+
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,165 @@
1
+ module Waves
2
+
3
+ #
4
+ # Controllers in Waves are simply classes that provide a request / response
5
+ # context for operating on a model. While models are essentially just a way
6
+ # to manage data in an application, controllers manage data in response to
7
+ # a request. For example, a controller updates a model instance using
8
+ # parameters from the request.
9
+ #
10
+ # Public controller methods simply return data (a resource), if necessary, that
11
+ # can be then used by views to determine how to render that data.
12
+ # Controllers do not determine which view will be invoked. They are
13
+ # independent of the view; one controller method might be suitable for
14
+ # several different views. In some cases, controllers can choose to
15
+ # directly modify the response and possibly even short-circuit the view
16
+ # entirely. A good example of this is a redirect.
17
+ #
18
+ # Controllers, like Views and Mappings, use the Waves::ResponseMixin to
19
+ # provide a rich context for working with the request and response objects.
20
+ # They can even call other controllers or views using the controllers method.
21
+ # In addition, they provide some basic reflection (access to the model and
22
+ # model_name that corresponds to the class name for the given model) and
23
+ # automatic parameter destructuring. This allows controller methods to access
24
+ # the request parameters as a hash, so that a POST variable named
25
+ # <tt>entry.title</tt> is accessed as <tt>params[:entry][:title]</tt>.
26
+ #
27
+ # Controllers often do not have to be explicitly defined. Instead, one or more
28
+ # default controllers can be defined that are used as exemplars for a given
29
+ # model. By default, the +waves+ command generates a single default, placed in
30
+ # the application's <tt>controllers/default.rb</tt> file. This can be modified
31
+ # to change the default behavior for all controllers. Alternatively, the
32
+ # <tt>rake generate:controller</tt> command can be used to explicitly define a
33
+ # controller.
34
+ #
35
+ # As an example, the code for the default controller is below for the Blog application.
36
+ #
37
+ # module Blog
38
+ # module Controllers
39
+ # class Default
40
+ #
41
+ # # Pick up the default controller methods, like param, url, etc.
42
+ # include Waves::Controllers::Mixin
43
+ #
44
+ # # This gets me the parameters associated with this model
45
+ # def attributes; params[model_name.singular.intern]; end
46
+ #
47
+ # # A simple generic delegator to the model
48
+ # def all; model.all; end
49
+ #
50
+ # # Find a specific instance based on a name or raise a 404
51
+ # def find( name ); model[ :name => name ] or not_found; end
52
+ #
53
+ # # Create a new instance based on the request params
54
+ # def create; model.create( attributes ); end
55
+ #
56
+ # # Update an existing record. find will raise a 404 if not found.
57
+ # def update( name )
58
+ # instance = find( name )
59
+ # instance.set( attributes )
60
+ # instance.save_changes
61
+ # end
62
+ #
63
+ # # Find and delete - or will raise a 404 if it doesn't exist
64
+ # def delete( name ); find( name ).destroy; end
65
+ #
66
+ # end
67
+ # end
68
+ # end
69
+ #
70
+ # Since the mapping file handles "glueing" controllers to views, controllers
71
+ # don't have to be at all concerned with views. They don't have to set
72
+ # instance variables, layouts, or contain logic to select the appropriate
73
+ # view based on the request. All they do is worry about updating the model
74
+ # when necessary based on the request.
75
+
76
+ module Controllers
77
+
78
+ #
79
+ # Waves::Controllers::Mixin adapts a controller class for use in mappings and provides utility methods.
80
+ # It is included in controllers autocreated by the Default foundation, so you do not need to include
81
+ # it in subclasses of the same.
82
+ #
83
+ # The utility methods include simple reflection to allow controller methods
84
+ # to be written generically (i.e., without reference to a specific model) and
85
+ # parameter destructuring for the request parameters.
86
+ #
87
+
88
+ module Mixin
89
+
90
+ attr_reader :request
91
+
92
+ include Waves::ResponseMixin
93
+
94
+ # When this mixin is included it adds a class method named +process+,
95
+ # which accepts a request object and a block. The +process+ method initializes the
96
+ # controller with the request, then evaluates the block using +instance_eval+. This allows the
97
+ # controller to be used from within a mapping lambda (i.e. a ResponseProxy).
98
+
99
+ def self.included( mod )
100
+ def mod.process( request, &block )
101
+ self.new( request ).instance_eval( &block )
102
+ end
103
+ end
104
+
105
+ def initialize( request )
106
+ @request = request
107
+ end
108
+
109
+ # The params variable is taken from the request object and "destructured", so that
110
+ # a parameter named 'blog.title' becomes:
111
+ #
112
+ # params['blog']['title']
113
+ #
114
+ # If you want to access the original parameters object, you can still do so using
115
+ # +request.params+ instead of simply +params+.
116
+ def params; @params ||= destructure(request.params); end
117
+
118
+ # Returns the name of the model corresponding to this controller by taking the basename
119
+ # of the module and converting it to snake case. If the model plurality is different than
120
+ # the controller, this will not, in fact, be the model name.
121
+ def model_name; self.class.basename.snake_case; end
122
+
123
+ # Returns the model corresponding to this controller by naively assuming that
124
+ # +model_name+ must be correct. This allows you to write generic controller methods such as:
125
+ #
126
+ # model.find( name )
127
+ #
128
+ # to find an instance of a given model. Again, the plurality of the controller and
129
+ # model must be the same for this to work.
130
+ def model; Waves.application.models[ model_name.intern ]; end
131
+
132
+ private
133
+
134
+ def destructure( hash )
135
+ destructured = {}
136
+ hash.keys.map { |key| key.split('.') }.each do |keys|
137
+ destructure_with_array_keys(hash, '', keys, destructured)
138
+ end
139
+ destructured
140
+ end
141
+
142
+ def destructure_with_array_keys( hash, prefix, keys, destructured )
143
+ if keys.length == 1
144
+ key = "#{prefix}#{keys.first}"
145
+ val = hash[key]
146
+ destructured[keys.first.intern] = case val
147
+ when String
148
+ val.strip
149
+ when Hash
150
+ val
151
+ when nil
152
+ raise key.inspect
153
+ end
154
+ else
155
+ destructured = ( destructured[keys.first.intern] ||= {} )
156
+ new_prefix = "#{prefix}#{keys.shift}."
157
+ destructure_with_array_keys( hash, new_prefix, keys, destructured )
158
+ end
159
+ end
160
+
161
+ end
162
+
163
+ end
164
+
165
+ end
@@ -0,0 +1,67 @@
1
+ module Waves
2
+
3
+ module Dispatchers
4
+
5
+ # A NotFoundError means what you think it means. The dispatchers included with Waves do not
6
+ # natively intercept this exception. Instead an exception handler must be registered in the application
7
+ # mappings. The Simple foundation registers a minimal handler, while the Default foundation registers
8
+ # a slightly fleshier one.
9
+ class NotFoundError < Exception ; end
10
+
11
+ # Redirect exceptions are rescued by the Waves dispatcher and used to set the
12
+ # response status and location.
13
+ class Redirect < Exception
14
+ attr_reader :path, :status
15
+ def initialize( path, status = '302' )
16
+ @path = path
17
+ @status = status
18
+ end
19
+ end
20
+
21
+ # Waves::Dispatchers::Base provides the basic request processing structure.
22
+ # All other Waves dispatchers should inherit from it. It creates a Waves request,
23
+ # determines whether to enclose the request processing in a mutex, benchmarks it,
24
+ # logs it, and handles common exceptions and redirects. Derived classes need only
25
+ # process the request within the +safe+ method, which must take a Waves::Request and return a Waves::Response.
26
+
27
+ class Base
28
+
29
+ # As with any Rack application, a Waves dispatcher must provide a call method
30
+ # that takes an +env+ parameter.
31
+ def call( env )
32
+ if Waves.config.synchronize?
33
+ Waves::Application.instance.synchronize { _call( env ) }
34
+ else
35
+ _call( env )
36
+ end
37
+ end
38
+
39
+ # Called by event driven servers like thin and ebb. Returns true if
40
+ # the server should run the request in a separate thread, as determined by
41
+ # Configurations::Mapping#threaded?
42
+ def deferred?( env )
43
+ Waves::Application.instance.mapping.threaded?( env )
44
+ end
45
+
46
+ private
47
+
48
+ def _call( env )
49
+ request = Waves::Request.new( env )
50
+ response = request.response
51
+ t = Benchmark.realtime do
52
+ begin
53
+ safe( request )
54
+ rescue Dispatchers::Redirect => redirect
55
+ response.status = redirect.status
56
+ response.location = redirect.path
57
+ end
58
+ end
59
+ Waves::Logger.info "#{request.method}: #{request.url} handled in #{(t*1000).round} ms."
60
+ response.finish
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ end
@@ -0,0 +1,81 @@
1
+ module Waves
2
+
3
+ module Dispatchers
4
+
5
+ #
6
+ # Waves::Dispatchers::Default matches requests against an application's mappings to
7
+ # determine what main action to take, as well as what before, after, always, and exception-handling
8
+ # blocks must run.
9
+ #
10
+ # The default dispatcher also attempts to set the content type based on the
11
+ # file extension used in the request URL. It does this using the class defined in
12
+ # the current configuration's +mime_types+ attribute, which defaults to Mongrel's
13
+ # MIME type handler.
14
+ #
15
+ # You can write your own dispatcher and use it in your application's configuration
16
+ # file. By default, they use the default dispatcher, like this:
17
+ #
18
+ # application do
19
+ # use Rack::ShowExceptions
20
+ # run Waves::Dispatchers::Default.new
21
+ # end
22
+ #
23
+
24
+ class Default < Base
25
+
26
+ # All dispatchers using the Dispatchers::Base to provide thread-safety, logging, etc.
27
+ # must provide a +safe+ method to handle creating a response from a request.
28
+ # Takes a Waves::Request and returns a Waves::Reponse
29
+ def safe( request )
30
+
31
+ response = request.response
32
+
33
+ Waves::Application.instance.reload if Waves::Application.instance.debug?
34
+ response.content_type = Waves::Application.instance.config.mime_types[ request.path ] || 'text/html'
35
+
36
+ mapping = Waves::Application.instance.mapping[ request ]
37
+
38
+ begin
39
+
40
+ mapping[:before].each do | block, args |
41
+ ResponseProxy.new(request).instance_exec(*args,&block)
42
+ end
43
+
44
+ request.not_found unless mapping[:action]
45
+
46
+ block, args = mapping[:action]
47
+ response.write( ResponseProxy.new(request).instance_exec(*args, &block) )
48
+
49
+ mapping[:after].each do | block, args |
50
+ ResponseProxy.new(request).instance_exec(*args,&block)
51
+ end
52
+
53
+ rescue Exception => e
54
+
55
+ handler = mapping[:handlers].detect do | exception, block, args |
56
+ e.is_a? exception
57
+ end
58
+ if handler
59
+ ResponseProxy.new(request).instance_exec(*handler[2], &handler[1])
60
+ else
61
+ raise e
62
+ end
63
+
64
+ ensure
65
+ mapping[:always].each do | block, args |
66
+ begin
67
+ ResponseProxy.new(request).instance_exec(*args,&block)
68
+ rescue Exception => e
69
+ Waves::Logger.info e.to_s
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,27 @@
1
+ module Waves
2
+ module Foundations
3
+ # The Default foundation supports the common MVC development pattern, a la Rails and Merb. Models, controllers, views, templates, and helpers live in the corresponding directories. When your code calls for a specific M, V, C, or H, Waves tries to load it from a file matching the snake-case of the constant name. If the file does not exist, Waves creates the constant from a sensible (and customizable) default.
4
+ #
5
+ # This foundation does not include any ORM configuration. You can include Waves::Layers::ORM::Sequel or custom configure your model.
6
+
7
+
8
+ module Default
9
+
10
+ def self.included( app )
11
+
12
+ app.instance_eval do
13
+
14
+ include Waves::Layers::Inflect::English
15
+ include Waves::Layers::Simple
16
+ include Waves::Layers::MVC
17
+ include Waves::Layers::DefaultErrors
18
+
19
+ end
20
+
21
+ Waves << app
22
+
23
+ end
24
+ end
25
+ end
26
+ end
27
+
@@ -0,0 +1,30 @@
1
+ module Waves
2
+
3
+ # A Waves Foundation provides enough functionality to allow a Waves application
4
+ # to run. At the bare minimum, this means creating configuration classes in the Configurations
5
+ # namespace, as is done in the Simple foundation
6
+ #
7
+ # Typically, a Foundation will include several Layers, perform any necessary
8
+ # configuration, and register the application with the Waves module
9
+ module Foundations
10
+
11
+ # The Simple foundation provides the bare minimum needed to run a Waves application.
12
+ # It is intended for use as the basis of more fully-featured foundations, but you can
13
+ # use it as a standalone where all the request processing is done directly in a
14
+ # mapping lambda.
15
+ module Simple
16
+
17
+ # On inclusion in a module, the Simple foundation includes Waves::Layers::Simple and
18
+ # registers the module as a Waves application.
19
+ def self.included( app )
20
+
21
+ app.instance_eval do
22
+ include Waves::Layers::Simple
23
+ end
24
+
25
+ Waves << app
26
+ end
27
+ end
28
+ end
29
+ end
30
+
@@ -0,0 +1,67 @@
1
+ module Waves
2
+ module Helpers
3
+ module AssetHelper
4
+ # Returns an html image tag for the +source+. The +source+ can be a full
5
+ # path or a file that exists in your public images directory. Note that
6
+ # specifying a filename without the extension is now deprecated in Rails.
7
+ # You can add html attributes using the +options+. The +options+ supports
8
+ # two additional keys for convienence and conformance:
9
+ #
10
+ # * <tt>:alt</tt> - If no alt text is given, the file name part of the
11
+ # +source+ is used (capitalized and without the extension)
12
+ # * <tt>:size</tt> - Supplied as "{Width}x{Height}", so "30x45" becomes
13
+ # width="30" and height="45". <tt>:size</tt> will be ignored if the
14
+ # value is not in the correct format.
15
+ #
16
+ # image_tag("icon.png") # =>
17
+ # <img src="/images/icon.png" alt="Icon" />
18
+ # image_tag("icon.png", :size => "16x10", :alt => "Edit Entry") # =>
19
+ # <img src="/images/icon.png" width="16" height="10" alt="Edit Entry" />
20
+ # image_tag("/icons/icon.gif", :size => "16x16") # =>
21
+ # <img src="/icons/icon.gif" width="16" height="16" alt="Icon" />
22
+ def image_tag(source, options = {})
23
+ options.symbolize_keys!
24
+
25
+ options[:src] = image_path(source)
26
+ options[:alt] ||= File.basename(options[:src], '.*').split('.').first.capitalize
27
+
28
+ if options[:size]
29
+ options[:width], options[:height] = options[:size].split("x") if options[:size] =~ %r{^\d+x\d+$}
30
+ options.delete(:size)
31
+ end
32
+
33
+ tag("img", options)
34
+ end
35
+
36
+ # Computes the path to an image asset in the public images directory.
37
+ # Full paths from the document root will be passed through.
38
+ # Used internally by image_tag to build the image path. Passing
39
+ # a filename without an extension is deprecated.
40
+ #
41
+ # image_path("edit.png") # => /images/edit.png
42
+ # image_path("icons/edit.png") # => /images/icons/edit.png
43
+ # image_path("/icons/edit.png") # => /icons/edit.png
44
+ def image_path(source)
45
+ compute_public_path(source, 'images', 'png')
46
+ end
47
+
48
+ private
49
+ def compute_public_path(source, dir, ext)
50
+ source = source.dup
51
+ source << ".#{ext}" if File.extname(source).blank?
52
+ unless source =~ %r{^[-a-z]+://}
53
+ source = "/#{dir}/#{source}" unless source[0] == ?/
54
+ asset_id = rails_asset_id(source)
55
+ source << '?' + asset_id if defined?(RAILS_ROOT) && !asset_id.blank?
56
+ # source = "#{ActionController::Base.asset_host}#{@controller.request.relative_url_root}#{source}"
57
+ end
58
+ source
59
+ end
60
+
61
+ def rails_asset_id(source)
62
+ ENV["WAVES_ASSET_ID"] || File.mtime("public/#{source}").to_i.to_s rescue ""
63
+ end
64
+
65
+ end
66
+ end
67
+ end