waw 0.2.2

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 (199) hide show
  1. data/LICENCE.rdoc +25 -0
  2. data/README.rdoc +32 -0
  3. data/bin/waw +32 -0
  4. data/bin/waw-profile +26 -0
  5. data/bin/waw-start +26 -0
  6. data/bin/wspec +33 -0
  7. data/layouts/empty/Rakefile +14 -0
  8. data/layouts/empty/config.ru +5 -0
  9. data/layouts/empty/config/commons.cfg +31 -0
  10. data/layouts/empty/config/devel.cfg +21 -0
  11. data/layouts/empty/ignore +7 -0
  12. data/layouts/empty/logs/dontforgetme +0 -0
  13. data/layouts/empty/resources/messages.rs +1 -0
  14. data/layouts/empty/test/wspec/site_respond.wspec +3 -0
  15. data/layouts/empty/test/wspec/test_all.rb +13 -0
  16. data/layouts/empty/waw.deploy +1 -0
  17. data/layouts/empty/waw.routing +6 -0
  18. data/layouts/static/dependencies +1 -0
  19. data/layouts/static/public/.wawaccess +18 -0
  20. data/layouts/static/public/css/style.css +0 -0
  21. data/layouts/static/public/images/dontforgetme +0 -0
  22. data/layouts/static/public/js/project.js +0 -0
  23. data/layouts/static/public/pages/.wawaccess +30 -0
  24. data/layouts/static/public/pages/404.wtpl +1 -0
  25. data/layouts/static/public/pages/index.wtpl +5 -0
  26. data/layouts/static/public/templates/.wawaccess +9 -0
  27. data/layouts/static/public/templates/layout.wtpl +17 -0
  28. data/layouts/static/test/wspec/static_pages_are_served.wspec +21 -0
  29. data/layouts/static/waw.routing +8 -0
  30. data/lib/waw.rb +99 -0
  31. data/lib/waw/commands/command.rb +115 -0
  32. data/lib/waw/commands/profile_command.rb +66 -0
  33. data/lib/waw/commands/start_command.rb +59 -0
  34. data/lib/waw/config.rb +110 -0
  35. data/lib/waw/controller.rb +25 -0
  36. data/lib/waw/controllers/action/action.rb +91 -0
  37. data/lib/waw/controllers/action/action_utils.rb +30 -0
  38. data/lib/waw/controllers/action/js_generation.rb +116 -0
  39. data/lib/waw/controllers/action_controller.rb +133 -0
  40. data/lib/waw/controllers/error/backtrace.rb +54 -0
  41. data/lib/waw/controllers/error_handler.rb +62 -0
  42. data/lib/waw/controllers/json_controller.rb +31 -0
  43. data/lib/waw/controllers/no_cache.rb +22 -0
  44. data/lib/waw/controllers/static/match.rb +80 -0
  45. data/lib/waw/controllers/static/waw_access.rb +235 -0
  46. data/lib/waw/controllers/static/waw_access_dsl.rb +48 -0
  47. data/lib/waw/controllers/static_controller.rb +37 -0
  48. data/lib/waw/default_config.cfg +14 -0
  49. data/lib/waw/environment_utils.rb +57 -0
  50. data/lib/waw/errors.rb +4 -0
  51. data/lib/waw/ext.rb +3 -0
  52. data/lib/waw/ext/core.rb +4 -0
  53. data/lib/waw/ext/core/hash.rb +47 -0
  54. data/lib/waw/ext/core/logger.rb +10 -0
  55. data/lib/waw/ext/core/module.rb +20 -0
  56. data/lib/waw/ext/core/object.rb +29 -0
  57. data/lib/waw/ext/rack.rb +19 -0
  58. data/lib/waw/ext/rack/builder.rb +43 -0
  59. data/lib/waw/ext/rack/delegator.rb +51 -0
  60. data/lib/waw/ext/rack/urlmap.rb +55 -0
  61. data/lib/waw/ext/wlang.rb +1 -0
  62. data/lib/waw/ext/wlang/hosted_language.rb +21 -0
  63. data/lib/waw/fullstate.rb +8 -0
  64. data/lib/waw/fullstate/on_class.rb +37 -0
  65. data/lib/waw/fullstate/on_instance.rb +27 -0
  66. data/lib/waw/fullstate/variable.rb +36 -0
  67. data/lib/waw/kern.rb +6 -0
  68. data/lib/waw/kern/app.rb +48 -0
  69. data/lib/waw/kern/empty/waw.deploy +0 -0
  70. data/lib/waw/kern/empty/waw.routing +1 -0
  71. data/lib/waw/kern/freezed_state.rb +32 -0
  72. data/lib/waw/kern/hooks.rb +53 -0
  73. data/lib/waw/kern/lifecycle.rb +248 -0
  74. data/lib/waw/kern/living_state.rb +87 -0
  75. data/lib/waw/kern/utils.rb +27 -0
  76. data/lib/waw/resource_collection.rb +100 -0
  77. data/lib/waw/restart.rb +32 -0
  78. data/lib/waw/routing.rb +43 -0
  79. data/lib/waw/routing/action_routing.rb +78 -0
  80. data/lib/waw/routing/dsl.rb +45 -0
  81. data/lib/waw/routing/feedback.rb +23 -0
  82. data/lib/waw/routing/form_validation_feedback.rb +36 -0
  83. data/lib/waw/routing/javascript.rb +17 -0
  84. data/lib/waw/routing/redirect.rb +26 -0
  85. data/lib/waw/routing/refresh.rb +17 -0
  86. data/lib/waw/routing/routing_rule.rb +16 -0
  87. data/lib/waw/scope_utils.rb +69 -0
  88. data/lib/waw/session.rb +51 -0
  89. data/lib/waw/testing.rb +1 -0
  90. data/lib/waw/tools/mail.rb +4 -0
  91. data/lib/waw/tools/mail/mail.rb +119 -0
  92. data/lib/waw/tools/mail/mail_agent.rb +123 -0
  93. data/lib/waw/tools/mail/mailbox.rb +62 -0
  94. data/lib/waw/tools/mail/template.rb +38 -0
  95. data/lib/waw/utils/dsl_helper.rb +116 -0
  96. data/lib/waw/validation.rb +175 -0
  97. data/lib/waw/validation/and_validator.rb +27 -0
  98. data/lib/waw/validation/array_validations.rb +38 -0
  99. data/lib/waw/validation/boolean_validator.rb +32 -0
  100. data/lib/waw/validation/comparison_validations.rb +45 -0
  101. data/lib/waw/validation/date_validator.rb +31 -0
  102. data/lib/waw/validation/default_validator.rb +30 -0
  103. data/lib/waw/validation/dsl_ruby_extensions.rb +11 -0
  104. data/lib/waw/validation/errors.rb +17 -0
  105. data/lib/waw/validation/ext.rb +3 -0
  106. data/lib/waw/validation/file_validator.rb +30 -0
  107. data/lib/waw/validation/float_validator.rb +19 -0
  108. data/lib/waw/validation/helpers.rb +67 -0
  109. data/lib/waw/validation/integer_validator.rb +16 -0
  110. data/lib/waw/validation/isin_validator.rb +24 -0
  111. data/lib/waw/validation/mandatory_validator.rb +17 -0
  112. data/lib/waw/validation/missing_validator.rb +17 -0
  113. data/lib/waw/validation/not_validator.rb +20 -0
  114. data/lib/waw/validation/or_validator.rb +34 -0
  115. data/lib/waw/validation/regexp_validator.rb +29 -0
  116. data/lib/waw/validation/same_validator.rb +16 -0
  117. data/lib/waw/validation/signature.rb +157 -0
  118. data/lib/waw/validation/size_validations.rb +44 -0
  119. data/lib/waw/validation/string_validator.rb +15 -0
  120. data/lib/waw/validation/validator.rb +48 -0
  121. data/lib/waw/wawgen.rb +2 -0
  122. data/lib/waw/wawgen/create.rb +166 -0
  123. data/lib/waw/wawgen/project.rb +25 -0
  124. data/lib/waw/wspec.rb +5 -0
  125. data/lib/waw/wspec/browser.rb +240 -0
  126. data/lib/waw/wspec/dsl.rb +201 -0
  127. data/lib/waw/wspec/html_analysis.rb +136 -0
  128. data/lib/waw/wspec/html_analysis/tag.rb +56 -0
  129. data/lib/waw/wspec/runner.rb +70 -0
  130. data/lib/waw/wspec/scenario.rb +35 -0
  131. data/lib/waw/wspec/suite.rb +54 -0
  132. data/test/bricks/error_handler/config/test.cfg +2 -0
  133. data/test/bricks/error_handler/logs/webapp.log +1411 -0
  134. data/test/bricks/error_handler/test/error_handler.wspec +16 -0
  135. data/test/bricks/error_handler/waw.deploy +1 -0
  136. data/test/bricks/error_handler/waw.routing +27 -0
  137. data/test/integration/waw_create_integration_test.rb +24 -0
  138. data/test/spec/assumptions_spec.rb +30 -0
  139. data/test/spec/controllers/action_controller_spec.rb +14 -0
  140. data/test/spec/controllers/static/waw_access_spec.rb +112 -0
  141. data/test/spec/environment_utils_spec.rb +15 -0
  142. data/test/spec/ext/core/hash_spec.rb +58 -0
  143. data/test/spec/fixtures.rb +41 -0
  144. data/test/spec/fixtures/action/config/default.cfg +2 -0
  145. data/test/spec/fixtures/action/lib/action_controller_test.rb +12 -0
  146. data/test/spec/fixtures/action/waw.deploy +1 -0
  147. data/test/spec/fixtures/action/waw.routing +6 -0
  148. data/test/spec/fixtures/empty/waw.deploy +0 -0
  149. data/test/spec/fixtures/empty/waw.routing +0 -0
  150. data/test/spec/fullstate/on_class_spec.rb +59 -0
  151. data/test/spec/fullstate/on_instance_spec.rb +59 -0
  152. data/test/spec/fullstate/session_spec.rb +43 -0
  153. data/test/spec/fullstate/variable_spec.rb +55 -0
  154. data/test/spec/resource_collection_spec.rb +50 -0
  155. data/test/spec/test_all.rb +9 -0
  156. data/test/spec/tools/mail/mail_agent_spec.rb +116 -0
  157. data/test/spec/tools/mail/mail_spec.rb +56 -0
  158. data/test/spec/tools/mail/mailbox_spec.rb +57 -0
  159. data/test/spec/tools/mail/template_spec.rb +47 -0
  160. data/test/spec/validation/array_validation_spec.rb +63 -0
  161. data/test/spec/validation/array_validator_spec.rb +17 -0
  162. data/test/spec/validation/date_validation_spec.rb +35 -0
  163. data/test/spec/validation/default_validation_spec.rb +37 -0
  164. data/test/spec/validation/disjuctive_validation_spec.rb +33 -0
  165. data/test/spec/validation/errors_spec.rb +37 -0
  166. data/test/spec/validation/file_validator_spec.rb +34 -0
  167. data/test/spec/validation/mail_validation_spec.rb +51 -0
  168. data/test/spec/validation/missing_validation_spec.rb +43 -0
  169. data/test/spec/validation/same_validation_spec.rb +24 -0
  170. data/test/spec/validation/signature_intuition_spec.rb +37 -0
  171. data/test/spec/validation/signature_spec.rb +164 -0
  172. data/test/spec/validation/validation_spec.rb +28 -0
  173. data/test/spec/wspec/html_analysis/tag_spec.rb +38 -0
  174. data/test/spec/wspec/html_analysis_spec.rb +170 -0
  175. data/test/unit/test_all.rb +8 -0
  176. data/test/unit/waw/app_test.rb +126 -0
  177. data/test/unit/waw/app_test/config/commons.cfg +2 -0
  178. data/test/unit/waw/app_test/config/devel.cfg +1 -0
  179. data/test/unit/waw/config_test.rb +54 -0
  180. data/test/unit/waw/controllers/action_controller_test.rb +76 -0
  181. data/test/unit/waw/controllers/action_test.rb +35 -0
  182. data/test/unit/waw/controllers/example_action_controller_test.rb +24 -0
  183. data/test/unit/waw/controllers/multiple_action_controller_test.rb +78 -0
  184. data/test/unit/waw/controllers/static/example/css/example.css +1 -0
  185. data/test/unit/waw/controllers/static/example/index.html +1 -0
  186. data/test/unit/waw/controllers/static/example/js/example.js +1 -0
  187. data/test/unit/waw/controllers/static/example/pages/hello.wtpl +1 -0
  188. data/test/unit/waw/controllers/static/waw_access_test.rb +76 -0
  189. data/test/unit/waw/ext/rack_test.rb +74 -0
  190. data/test/unit/waw/resource_collection_test.rb +49 -0
  191. data/test/unit/waw/resources.txt +4 -0
  192. data/test/unit/waw/routing/routing_test.rb +26 -0
  193. data/test/unit/waw/utils/dsl_helper_test.rb +79 -0
  194. data/test/unit/waw/utils/dsl_helper_test_extensions1.rb +4 -0
  195. data/test/unit/waw/validation/signature_test.rb +193 -0
  196. data/test/unit/waw/validation_test.rb +319 -0
  197. data/test/unit/waw/wspec/html_analysis_test.html +81 -0
  198. data/test/unit/waw/wspec/html_analysis_test.rb +26 -0
  199. metadata +272 -0
@@ -0,0 +1,115 @@
1
+ require 'optparse'
2
+ require 'fileutils'
3
+ module Waw
4
+ module Commands
5
+ class Command
6
+
7
+ # The verbose level
8
+ attr_accessor :verbose
9
+
10
+ # Show stack traces?
11
+ attr_accessor :trace
12
+
13
+ # Creates an empty command instance
14
+ def initialize
15
+ @verbose = false
16
+ @buffer = STDOUT
17
+ end
18
+
19
+ # Parses commandline options provided as an array of Strings.
20
+ def options
21
+ @options ||= OptionParser.new do |opt|
22
+ opt.program_name = File.basename $0
23
+ opt.version = Waw::VERSION
24
+ opt.release = nil
25
+ opt.summary_indent = ' ' * 4
26
+ banner = self.banner
27
+ opt.banner = banner.gsub(/^[ \t]+/, "")
28
+
29
+ opt.separator nil
30
+ opt.separator "Options:"
31
+
32
+ add_options(opt)
33
+
34
+ opt.on("--trace", "Display stack trace on error?") do |value|
35
+ @trace = true
36
+ end
37
+
38
+ opt.on("--verbose", "-v", "Display extra progress as we progress") do |value|
39
+ @verbose = true
40
+ end
41
+
42
+ # No argument, shows at tail. This will print an options summary.
43
+ # Try it and see!
44
+ opt.on_tail("-h", "--help", "Show this message") do
45
+ puts options
46
+ exit
47
+ end
48
+
49
+ # Another typical switch to print the version.
50
+ opt.on_tail("--version", "Show version") do
51
+ puts opt.program_name << Waw::VERSION << " (c) University of Louvain, Bernard & Louis Lambeau"
52
+ exit
53
+ end
54
+
55
+ opt.separator nil
56
+ end
57
+ end
58
+
59
+ # Runs the command
60
+ def run(requester_file, argv)
61
+ @requester_file = requester_file
62
+ check_command_policy
63
+ __run(requester_file, options.parse!(argv))
64
+ rescue OptionParser::InvalidOption => ex
65
+ exit ex.message
66
+ rescue SystemExit
67
+ rescue Exception => ex
68
+ error <<-EOF
69
+ A severe error occured. Please report this to the developers.
70
+ Try --trace if the trace does not appear
71
+
72
+ #{ex.class}: #{ex.message}
73
+ EOF
74
+ error ex.backtrace.join("\n") if trace
75
+ end
76
+
77
+ def shell_exec(what)
78
+ info "shell: #{what}" if verbose
79
+ info `#{what}`
80
+ end
81
+
82
+ # Exits with a message, showing options if required
83
+ def exit(msg = nil, show_options=true)
84
+ info msg if msg
85
+ puts options if show_options
86
+ Kernel.exit(-1)
87
+ end
88
+
89
+ def info(msg)
90
+ @buffer << msg.gsub(/^[ \t]+/, '') << "\n"
91
+ end
92
+ alias :error :info
93
+
94
+ # Contribute to options
95
+ def add_options(opt)
96
+ end
97
+
98
+ # Returns the command banner
99
+ def banner
100
+ raise "Command.banner should be overriden by subclasses"
101
+ end
102
+
103
+ # Checks that the command may be safely executed!
104
+ def check_command_policy
105
+ raise "Command.check_command_policy should be overriden"
106
+ end
107
+
108
+ # Runs the sub-class defined command
109
+ def __run(requester_file, arguments)
110
+ raise "Command._run should be overriden"
111
+ end
112
+
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,66 @@
1
+ require 'waw/wspec'
2
+ require 'waw/commands/start_command'
3
+ module Waw
4
+ module Commands
5
+ class ProfileCommand < Command
6
+
7
+ def banner
8
+ <<-EOF
9
+ Usage: [waw-]profile [options]
10
+ EOF
11
+ end
12
+
13
+ # Start command is always safe
14
+ def check_command_policy
15
+ true
16
+ end
17
+
18
+ # Ignores a given location?
19
+ def ignore?(location, visited)
20
+ visited[location] or /\.(gif|zip|pdf|jpg|csv)$/ =~ location
21
+ end
22
+
23
+ # Recursively visits the whole website
24
+ def visit(browser, location, visited = {})
25
+ return if ignore?(location, visited)
26
+ visited[location] = true
27
+ browser.location = location
28
+ unless browser.is200
29
+ puts "Hohoho, I've found a lost internal link #{location}"
30
+ return
31
+ else
32
+ puts "Visiting #{location}" if verbose
33
+ browser.all_internal_links.each do |link|
34
+ visit(browser, link[:href], visited)
35
+ end
36
+ end
37
+ end
38
+
39
+ # Runs the sub-class defined command
40
+ def __run(requester_file, arguments)
41
+ require 'waw/wspec/browser'
42
+
43
+ # Start the server first
44
+ thread, waw_kernel = ::Waw::Commands::StartCommand.new.waw_start(requester_file, verbose)
45
+ visited, browser, location = {}, ::Waw::WSpec::Browser.new, waw_kernel.config.web_base
46
+
47
+ # Launch the visit
48
+ t1 = Time.now
49
+ visit(browser, location, visited)
50
+ t2 = Time.now
51
+
52
+ # Stop the server now
53
+ thread.exit
54
+
55
+ # Show statistics
56
+ req_by_sec = visited.size.to_f/(t2-t1)
57
+ avg_by_sec = (t2-t1)/visited.size
58
+
59
+ puts "#{visited.size} pages visited in #{t2-t1} seconds (#{req_by_sec} req./sec., #{avg_by_sec} sec./req.)"
60
+ rescue Interrupt => ex
61
+ info "waw-profile stopping now... ciao!" if verbose
62
+ end
63
+
64
+ end # module ProfileCommand
65
+ end # module Commands
66
+ end # module Waw
@@ -0,0 +1,59 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ module Waw
4
+ module Commands
5
+ class StartCommand < Command
6
+
7
+ def banner
8
+ <<-EOF
9
+ Usage: [waw-]start [options]
10
+ EOF
11
+ end
12
+
13
+ # Start command is always safe
14
+ def check_command_policy
15
+ true
16
+ end
17
+
18
+ # Executes the waw-start command and returns the running thread
19
+ def waw_start(requester_file, verbose = true)
20
+ waw_kernel = Waw.autoload(requester_file)
21
+ t = Thread.new(waw_kernel) do |app|
22
+ begin
23
+ server = Rack::Handler::Mongrel
24
+ rescue LoadError => e
25
+ server = Rack::Handler::WEBrick
26
+ end
27
+ options = {:Port => app.config.web_port, :Host => "0.0.0.0", :AccessLog => []}
28
+ server.run app, options
29
+ end
30
+ try, ok = 0, false
31
+ begin
32
+ info "Attempting to reach the web server..." if verbose
33
+ ::Net::HTTP.get(URI.parse(waw_kernel.config.web_base))
34
+ ok = true
35
+ rescue Errno::ECONNREFUSED => ex
36
+ sleep 0.1
37
+ end until (ok or (try += 1)>10)
38
+ if ok
39
+ if verbose
40
+ info "Your web application has been started successfully"
41
+ info "Have a look at #{waw_kernel.config.web_base}"
42
+ info "Enjoy waw!"
43
+ end
44
+ [t, waw_kernel]
45
+ else
46
+ raise Waw::Error, "Unable to reach the web server after having been started"
47
+ end
48
+ end
49
+
50
+ # Runs the sub-class defined command
51
+ def __run(requester_file, arguments)
52
+ waw_start(requester_file)[0].join
53
+ rescue Interrupt => ex
54
+ info "waw-start stopping now... ciao!"
55
+ end
56
+
57
+ end # class StartCommand
58
+ end # module Commans
59
+ end # module Waw
@@ -0,0 +1,110 @@
1
+ module Waw
2
+ # Implements waw configuration utility
3
+ class Config
4
+
5
+ # Implementation of the config domain specific language
6
+ class DSL
7
+
8
+ # Creates a DSL instance
9
+ def initialize(config)
10
+ @config = config
11
+ end
12
+
13
+ # When a method is missing, install config parameter
14
+ def method_missing(name, *args, &block)
15
+ if args.length==0 and block.nil?
16
+ @config.send(name)
17
+ elsif args.length==0
18
+ @config.install_configuration_property(name, block)
19
+ elsif block
20
+ raise WawConfigurationError, "Bad config usage on #{name}"
21
+ else
22
+ @config.install_configuration_property(name, args.size==1 ? args[0] : args)
23
+ end
24
+ end
25
+
26
+ end # class DSL
27
+
28
+ # Initialize a configuration instance. If merge_default is set to true,
29
+ # the default configuration file is automatically loaded.
30
+ def initialize(app, merge_default = true)
31
+ raise ArgumentError, "Waw application required as first argument" unless app.respond_to?(:root_folder)
32
+ @wawapp = app
33
+ self.merge_file(File.join(File.dirname(__FILE__), 'default_config.cfg')) if merge_default
34
+ end
35
+
36
+ # Raises a configuration error
37
+ def config_error(name, message)
38
+ raise ConfigurationError, message
39
+ end
40
+
41
+ # Checks if a configuration property is known
42
+ def knows?(name)
43
+ self.respond_to?(name.to_s.to_sym)
44
+ end
45
+
46
+ # Returns the configuration property under name,
47
+ # or returns default if the config does not know that name
48
+ def ensure(name, default)
49
+ knows?(name) ? self.send(name) : default
50
+ end
51
+
52
+ # Installs a configuration parameter
53
+ def install_configuration_property(name, value)
54
+ case name
55
+ when :load_path
56
+ value = [value] unless Array===value
57
+ value = value.collect{|val| File.expand_path(File.join(@wawapp.root_folder, val))}
58
+ $LOAD_PATH.unshift(*value)
59
+ when :requires
60
+ value = [value] unless Array===value
61
+ value.each{|f| require(f)}
62
+ when :log_dir
63
+ config_error(name, "log_dir is expected to be a string") unless String===value
64
+ # config_error(name, "Unable to access log_dir #{value}") unless File.exists?(value) and
65
+ # File.directory?(value) and
66
+ # File.writable?(value)
67
+ when :log_file
68
+ config_error(name, "log_file is expected to be a string") unless String===value
69
+ when :log_level
70
+ config_error(name, "Bad log_level #{value}") unless value>=0 and value<=5
71
+ when :log_frequency
72
+ config_error(name, "Bad log_frequency #{value}") unless %w{daily weekly monthly}.include?(value)
73
+ when :web_domain, :web_base
74
+ config_error(name, "web_domain is expected to be a string") unless String===value
75
+ when :rack_session
76
+ config_error(name, "rack_session is expected to be true or false") unless true==value or false==value
77
+ when :rack_session_expire
78
+ config_error(name, "rack_session_expire is expected to be an Integer") unless Integer===value
79
+ end
80
+ instance_eval "@#{name} = value"
81
+ instance_eval <<-EOF
82
+ def #{name}(force_array = false)
83
+ value = @#{name}
84
+ if Proc===value
85
+ self.instance_eval &value
86
+ else
87
+ force_array ? (Array===value ? value : [value]) : value
88
+ end
89
+ end
90
+ EOF
91
+ end
92
+
93
+ # Merges the configuration with a given configuration string
94
+ def merge(config_str)
95
+ begin
96
+ DSL.new(self).instance_eval config_str
97
+ rescue ConfigurationError => ex
98
+ raise ex
99
+ end
100
+ self
101
+ end
102
+
103
+ # Merges the configuration with a given configuration file
104
+ def merge_file(config_file)
105
+ raise ArgumentError, "Config file does not exists" unless File.exists?(config_file)
106
+ merge File.read(config_file)
107
+ end
108
+
109
+ end # class Config
110
+ end # module Waw
@@ -0,0 +1,25 @@
1
+ module Waw
2
+
3
+ #
4
+ # Controller of a web application, designing a number of typical services.
5
+ #
6
+ class Controller
7
+ include Waw::EnvironmentUtils
8
+ include ::Rack::Delegator
9
+
10
+ # Handler for Rack calls to the controller
11
+ def call(env)
12
+ result = execute(env, request, response)
13
+ raise WawError, "Controller #{self.class} returned an empty result" unless result
14
+ raise WawError, "Controller #{self.class} returned an invalid result #{result.inspect}" unless Array===result
15
+ result
16
+ end
17
+
18
+ # Executes the controller on a Rack::Request and Rack::Response pair
19
+ def execute(env, request, response)
20
+ raise "Should be subclassed"
21
+ end
22
+
23
+ end # class Controller
24
+
25
+ end # module Waw
@@ -0,0 +1,91 @@
1
+ module Waw
2
+ class ActionController < Waw::Controller
3
+ #
4
+ # A Web action, inside an ActionController.
5
+ #
6
+ class Action
7
+
8
+ # Action controller
9
+ attr_reader :controller
10
+
11
+ # Action name
12
+ attr_reader :name
13
+
14
+ # Action signature (pre-conditions and validation)
15
+ attr_reader :signature
16
+
17
+ # Action routing
18
+ attr_reader :routing
19
+
20
+ # Creates an action instance
21
+ def initialize(name, signature, routing, controller, method)
22
+ @name, @signature, @routing = name, signature, routing
23
+ @controller, @method = controller, method
24
+ @routing = ::Waw::Routing::ActionRouting.new unless @routing
25
+ end
26
+
27
+ # Returns a unique id for this action in the architecture
28
+ def id
29
+ "#{controller.url}/#{name}"[1..-1].gsub('/', '_')
30
+ end
31
+
32
+ # Builds a href for this action, with optional parameters
33
+ def href(params = nil)
34
+ "#{controller.url}/#{name}" << (params ? "?#{params.to_url_query}" : "")
35
+ end
36
+ alias :url :href
37
+ alias :uri :href
38
+
39
+ # Factors the ajax link for invoking this action in a <a onclick="...">
40
+ def ajax_link(arguments = {})
41
+ buffer = ""
42
+ arguments.each_pair {|k, v| buffer << ", '#{k}' : '#{v}'"}
43
+ "javascript:#{id}({#{buffer[2..-1]}}, '##{id}')"
44
+ end
45
+
46
+ # Factors the ajax code for preparing a formulary
47
+ def ajax_form_preparer(opts = {})
48
+ form_id = opts[:form_id] || id
49
+ <<-EOF
50
+ <script type="text/javascript">
51
+ $(document).ready(function() {
52
+ $("form##{form_id}").submit(function() {
53
+ #{id}($("form##{form_id}").serialize(), "form##{form_id}");
54
+ return false;
55
+ });
56
+ });
57
+ </script>
58
+ EOF
59
+ end
60
+
61
+ # Factors a javascript call to the associated action
62
+ def ajax_action_call(opts = {})
63
+ form_id = opts[:form_id] || id
64
+ "#{id}($(\"form##{form_id}\").serialize(), \"form##{form_id}\");"
65
+ end
66
+
67
+ # Factors the ajax code to submit the formulary
68
+ def ajax_form_submit(opts = {})
69
+ form_id = opts[:form_id] || id
70
+ "javascript:$('form##{form_id}').submit()"
71
+ end
72
+
73
+ # Executes the action inside a controller and using parameters
74
+ def execute(params = {})
75
+ ok, values = @signature.apply(params)
76
+ if ok
77
+ # validation is ok, merge params and continue
78
+ [:success, @method.bind(controller.instance).call(params.merge!(values))]
79
+ else
80
+ # validation is ko
81
+ [:"validation-ko", values]
82
+ end
83
+ rescue ::Waw::Validation::KO => ex
84
+ [:"validation-ko", ex.failed]
85
+ rescue ::Waw::Validation::Error => ex
86
+ [:"validation-error", ex.failed]
87
+ end
88
+
89
+ end # class Action
90
+ end # class ActionController
91
+ end # module Waw