merb 0.4.2 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. data/README +21 -14
  2. data/Rakefile +157 -108
  3. data/SVN_REVISION +1 -0
  4. data/app_generators/merb/templates/Rakefile +20 -4
  5. data/app_generators/merb/templates/app/views/exceptions/internal_server_error.html.erb +1 -1
  6. data/app_generators/merb/templates/config/boot.rb +1 -1
  7. data/app_generators/merb/templates/config/dependencies.rb +3 -3
  8. data/app_generators/merb/templates/config/merb.yml +5 -0
  9. data/app_generators/merb/templates/config/merb_init.rb +3 -3
  10. data/app_generators/merb/templates/script/destroy +3 -0
  11. data/app_generators/merb/templates/script/generate +1 -1
  12. data/app_generators/merb/templates/spec/spec_helper.rb +2 -2
  13. data/app_generators/merb/templates/test/test_helper.rb +1 -1
  14. data/app_generators/merb_plugin/merb_plugin_generator.rb +4 -0
  15. data/bin/merb +1 -3
  16. data/lib/merb.rb +144 -76
  17. data/lib/merb/abstract_controller.rb +6 -5
  18. data/lib/merb/assets.rb +119 -0
  19. data/lib/merb/boot_loader.rb +217 -0
  20. data/lib/merb/caching.rb +1 -1
  21. data/lib/merb/caching/action_cache.rb +1 -1
  22. data/lib/merb/caching/fragment_cache.rb +1 -1
  23. data/lib/merb/caching/store/file_cache.rb +1 -1
  24. data/lib/merb/config.rb +290 -0
  25. data/lib/merb/controller.rb +5 -5
  26. data/lib/merb/core_ext/get_args.rb +1 -0
  27. data/lib/merb/core_ext/hash.rb +182 -169
  28. data/lib/merb/core_ext/kernel.rb +57 -26
  29. data/lib/merb/dispatcher.rb +6 -6
  30. data/lib/merb/drb_server.rb +1 -1
  31. data/lib/merb/generators/merb_generator_helpers.rb +7 -6
  32. data/lib/merb/logger.rb +1 -1
  33. data/lib/merb/mail_controller.rb +3 -4
  34. data/lib/merb/mailer.rb +2 -2
  35. data/lib/merb/mixins/basic_authentication.rb +2 -2
  36. data/lib/merb/mixins/controller.rb +1 -1
  37. data/lib/merb/mixins/general_controller.rb +13 -20
  38. data/lib/merb/mixins/inline_partial.rb +32 -0
  39. data/lib/merb/mixins/render.rb +3 -3
  40. data/lib/merb/mixins/responder.rb +1 -1
  41. data/lib/merb/mixins/view_context.rb +159 -33
  42. data/lib/merb/mongrel_handler.rb +9 -9
  43. data/lib/merb/plugins.rb +1 -1
  44. data/lib/merb/request.rb +25 -1
  45. data/lib/merb/router.rb +264 -226
  46. data/lib/merb/server.rb +66 -560
  47. data/lib/merb/session/cookie_store.rb +14 -13
  48. data/lib/merb/session/mem_cache_session.rb +20 -10
  49. data/lib/merb/session/memory_session.rb +21 -11
  50. data/lib/merb/template.rb +2 -2
  51. data/lib/merb/template/erubis.rb +3 -33
  52. data/lib/merb/template/haml.rb +8 -3
  53. data/lib/merb/test/fake_request.rb +8 -3
  54. data/lib/merb/test/helper.rb +66 -22
  55. data/lib/merb/test/rspec.rb +9 -155
  56. data/lib/merb/test/rspec_matchers/controller_matchers.rb +117 -0
  57. data/lib/merb/test/rspec_matchers/markup_matchers.rb +98 -0
  58. data/lib/merb/upload_handler.rb +2 -1
  59. data/lib/merb/version.rb +38 -3
  60. data/lib/merb/view_context.rb +1 -2
  61. data/lib/tasks/merb.rake +11 -11
  62. data/merb_generators/part_controller/USAGE +5 -0
  63. data/merb_generators/part_controller/part_controller_generator.rb +27 -0
  64. data/merb_generators/part_controller/templates/controller.rb +8 -0
  65. data/merb_generators/part_controller/templates/helper.rb +5 -0
  66. data/merb_generators/part_controller/templates/index.html.erb +3 -0
  67. data/rspec_generators/merb_controller_test/merb_controller_test_generator.rb +1 -1
  68. data/script/destroy +14 -0
  69. data/script/generate +14 -0
  70. data/spec/fixtures/controllers/dispatch_spec_controllers.rb +9 -1
  71. data/spec/fixtures/controllers/render_spec_controllers.rb +5 -5
  72. data/spec/fixtures/models/router_spec_models.rb +10 -0
  73. data/spec/merb/abstract_controller_spec.rb +2 -2
  74. data/spec/merb/assets_spec.rb +207 -0
  75. data/spec/merb/caching_spec.rb +2 -2
  76. data/spec/merb/controller_spec.rb +7 -2
  77. data/spec/merb/cookie_store_spec.rb +1 -1
  78. data/spec/merb/core_ext/class_spec.rb +97 -0
  79. data/spec/merb/core_ext/enumerable_spec.rb +27 -0
  80. data/spec/merb/core_ext/hash_spec.rb +251 -0
  81. data/spec/merb/core_ext/inflector_spec.rb +34 -0
  82. data/spec/merb/core_ext/kernel_spec.rb +25 -0
  83. data/spec/merb/core_ext/numeric_spec.rb +26 -0
  84. data/spec/merb/core_ext/object_spec.rb +47 -0
  85. data/spec/merb/core_ext/string_spec.rb +22 -0
  86. data/spec/merb/core_ext/symbol_spec.rb +7 -0
  87. data/spec/merb/dependency_spec.rb +22 -0
  88. data/spec/merb/dispatch_spec.rb +23 -12
  89. data/spec/merb/fake_request_spec.rb +8 -0
  90. data/spec/merb/generator_spec.rb +140 -21
  91. data/spec/merb/handler_spec.rb +5 -5
  92. data/spec/merb/mail_controller_spec.rb +3 -3
  93. data/spec/merb/render_spec.rb +1 -1
  94. data/spec/merb/responder_spec.rb +3 -3
  95. data/spec/merb/router_spec.rb +260 -191
  96. data/spec/merb/server_spec.rb +5 -5
  97. data/spec/merb/upload_handler_spec.rb +7 -0
  98. data/spec/merb/version_spec.rb +33 -0
  99. data/spec/merb/view_context_spec.rb +217 -59
  100. data/spec/spec_generator_helper.rb +15 -0
  101. data/spec/spec_helper.rb +5 -3
  102. data/spec/spec_helpers/url_shared_behaviour.rb +5 -7
  103. metadata +32 -7
  104. data/lib/merb/caching/store/memcache.rb +0 -20
  105. data/lib/merb/mixins/form_control.rb +0 -332
  106. data/lib/patch +0 -69
  107. data/spec/merb/core_ext_spec.rb +0 -464
  108. data/spec/merb/form_control_mixin_spec.rb +0 -431
@@ -0,0 +1,119 @@
1
+ module Merb
2
+ module Assets
3
+
4
+ # Returns true if assets should be bundled (e.g., production mode or
5
+ # :bundle_assets is explicitly enabled), false if not.
6
+ def self.bundle?
7
+ (Merb::Config[:environment] == :production) ||
8
+ (!!Merb::Config[:bundle_assets])
9
+ end
10
+
11
+ # Helpers for handling asset files.
12
+ module AssetHelpers
13
+ # :nodoc:
14
+ ASSET_FILE_EXTENSIONS = {
15
+ :javascript => ".js",
16
+ :stylesheet => ".css"
17
+ }
18
+
19
+ # Returns the URI path to a particular asset file. If +local_path+ is
20
+ # true, returns the path relative to the Merb.root, not the public
21
+ # directory. Uses the path_prefix, if any is configured.
22
+ #
23
+ # asset_path(:javascript, :dingo) #=> "/javascripts/dingo.js"
24
+ # asset_path(:javascript, :dingo, true) #=> "public/javascripts/dingo.js"
25
+ def asset_path(asset_type, filename, local_path = false)
26
+ filename = filename.to_s
27
+ if filename !~ /#{'\\' + ASSET_FILE_EXTENSIONS[asset_type]}\Z/
28
+ filename << ASSET_FILE_EXTENSIONS[asset_type]
29
+ end
30
+ filename = "/#{asset_type}s/#{filename}"
31
+ if local_path
32
+ return "public#{filename}"
33
+ else
34
+ return "#{Merb::Config[:path_prefix]}#{filename}"
35
+ end
36
+ end
37
+ end
38
+
39
+ # An abstract class for bundling text assets into single files.
40
+ class AbstractAssetBundler
41
+ class << self
42
+
43
+ # Add a post-bundle callback, for example to run a Javascript or CSS
44
+ # compressor on the bundled file:
45
+ #
46
+ # Merb::Assets::JavascriptAssetBundler.add_callback do |filename|
47
+ # `yuicompressor #{filename}`
48
+ # end
49
+ def add_callback(&block)
50
+ callbacks << block
51
+ end
52
+ alias_method :after_bundling, :add_callback
53
+
54
+ # An array of any existing callbacks.
55
+ def callbacks
56
+ @callbacks ||= []
57
+ return @callbacks
58
+ end
59
+
60
+ # The type of asset for which the bundler is responsible.
61
+ def asset_type
62
+ raise NotImplementedError, "should return a symbol for the first argument to be passed to asset_path"
63
+ end
64
+ end
65
+
66
+ # Create a new asset bundler, which will produce a bundled file containing
67
+ # the contents of +files+. If +name+ is +true+ (as in, is an instance of
68
+ # +TrueClass+), the filename is written out as "all", otherwise +name+
69
+ # is coerced into a string.
70
+ def initialize(name, *files)
71
+ @bundle_name = name == true ? :all : name
72
+ @bundle_filename = asset_path(self.class.asset_type, @bundle_name, true)
73
+ @files = files.map { |f| asset_path(self.class.asset_type, f, true) }
74
+ end
75
+
76
+ # Creates the new bundled file, executes all the callbacks, and returns
77
+ # the name of the bundled file.
78
+ def bundle!
79
+ # TODO: Move this file check out into an in-memory cache. Also, push it out to the helper level so we don't have to create the helper object.
80
+ unless File.exist?(@bundle_filename)
81
+ bundle_files(@bundle_filename, *@files)
82
+ self.class.callbacks.each { |c| c.call(@bundle_filename) }
83
+ end
84
+ return @bundle_name
85
+ end
86
+
87
+ protected
88
+
89
+ include Merb::Assets::AssetHelpers # for asset_path
90
+
91
+ # Bundle all the filenames in +files+ into +filename+.
92
+ def bundle_files(filename, *files)
93
+ File.open(filename, "w") do |f|
94
+ files.each { |file| f.puts(File.read(file)) }
95
+ end
96
+ end
97
+
98
+ end
99
+
100
+ # Bundles javascripts into a single file:
101
+ #
102
+ # javascripts/#{name}.js
103
+ class JavascriptAssetBundler < AbstractAssetBundler
104
+ def self.asset_type
105
+ :javascript
106
+ end
107
+ end
108
+
109
+ # Bundles stylesheets into a single file:
110
+ #
111
+ # stylesheets/#{name}.css
112
+ class StylesheetAssetBundler < AbstractAssetBundler
113
+ def self.asset_type
114
+ :stylesheet
115
+ end
116
+ end
117
+
118
+ end
119
+ end
@@ -0,0 +1,217 @@
1
+ module Merb
2
+ module GlobalHelper;end
3
+
4
+ module BootLoader
5
+ class << self
6
+
7
+ def initialize_merb
8
+ require 'merb'
9
+ @mtime = Time.now if Merb::Config[:reloader] == true
10
+ # Register session types before merb_init.rb so that any additional
11
+ # session stores will be added to the end of the list and become the
12
+ # default.
13
+ register_session_type('memory',
14
+ Merb.framework_root / "merb" / "session" / "memory_session",
15
+ "Using in-memory sessions; sessions will be lost whenever the server stops.")
16
+ register_session_type('mem_cache',
17
+ Merb.framework_root / "merb" / "session" / "mem_cache_session",
18
+ "Using MemCache distributed memory sessions")
19
+ register_session_type('cookie', # Last session type becomes the default
20
+ Merb.framework_root / "merb" / "session" / "cookie_store",
21
+ "Using 'share-nothing' cookie sessions (4kb limit per client)")
22
+ require Merb.root / 'config/merb_init.rb'
23
+ add_controller_mixins
24
+ end
25
+
26
+ def max_mtime( files = [] )
27
+ files.map{ |file| File.mtime(file) rescue @mtime }.max
28
+ end
29
+
30
+ def register_session_type(name, file, description = nil)
31
+ @registered_session_types ||= YAML::Omap.new
32
+ @registered_session_types[name] = {
33
+ :file => file,
34
+ :description => (description || "Using #{name} sessions")
35
+ }
36
+ end
37
+
38
+ def add_controller_mixins
39
+ types = @registered_session_types
40
+ Merb::Controller.class_eval do
41
+ lib = File.join(Merb.framework_root, 'merb')
42
+ session_store = Merb::Config[:session_store].to_s
43
+ if ["", "false"].include?(session_store)
44
+ puts "Not Using Sessions"
45
+ elsif reg = types[session_store]
46
+ if session_store == "cookie"
47
+ unless Merb::Config[:session_secret_key] && (Merb::Config[:session_secret_key].length >= 16)
48
+ puts("You must specify a session_secret_key in your merb.yml, and it must be at least 16 characters\nbailing out...")
49
+ exit!
50
+ end
51
+ Merb::Controller.session_secret_key = Merb::Config[:session_secret_key]
52
+ end
53
+ require reg[:file]
54
+ include ::Merb::SessionMixin
55
+ puts reg[:description]
56
+ else
57
+ puts "Session store not found, '#{Merb::Config[:session_store]}'."
58
+ puts "Defaulting to CookieStore Sessions"
59
+ unless Merb::Config[:session_secret_key] && (Merb::Config[:session_secret_key].length >= 16)
60
+ puts("You must specify a session_secret_key in your merb.yml, and it must be at least 16 characters\nbailing out...")
61
+ exit!
62
+ end
63
+ Merb::Controller.session_secret_key = Merb::Config[:session_secret_key]
64
+ require types['cookie'][:file]
65
+ include ::Merb::SessionMixin
66
+ puts "(plugin not installed?)"
67
+ end
68
+
69
+ if Merb::Config[:basic_auth]
70
+ require lib + "/mixins/basic_authentication"
71
+ include ::Merb::AuthenticationMixin
72
+ puts "Basic Authentication mixed in"
73
+ end
74
+ end
75
+ end
76
+
77
+ def after_app_loads(&block)
78
+ @after_app_blocks ||= []
79
+ @after_app_blocks << block
80
+ end
81
+
82
+ def app_loaded?
83
+ @app_loaded
84
+ end
85
+
86
+ def load_action_arguments(klasses = Merb::Controller._subclasses)
87
+ begin
88
+ klasses.each do |controller|
89
+ controller = Object.full_const_get(controller)
90
+ controller.action_argument_list = {}
91
+ controller.callable_actions.each do |action, bool|
92
+ controller.action_argument_list[action.to_sym] = ParseTreeArray.translate(controller, action).get_args
93
+ end
94
+ end
95
+ rescue
96
+ klasses.each { |controller| Object.full_const_get(controller).action_argument_list = {} }
97
+ end if defined?(ParseTreeArray)
98
+ end
99
+
100
+ def template_paths(type = "*[a-zA-Z]")
101
+ # This gets all templates set in the controllers template roots
102
+ template_paths = Merb::AbstractController._abstract_subclasses.map do |klass|
103
+ Object.full_const_get(klass)._template_root
104
+ end.uniq.map do |path|
105
+ Dir["#{path}/**/#{type}"]
106
+ end
107
+
108
+ # This gets the templates that might be created outside controllers
109
+ # template roots. eg app/views/shared/*
110
+ template_paths << Dir["#{Merb.root}/app/views/**/*[a-zA-Z]"] if type == "*"
111
+
112
+ template_paths.flatten.compact.uniq || []
113
+ end
114
+
115
+ def load_controller_template_path_cache
116
+ Merb::AbstractController.reset_template_path_cache!
117
+
118
+ template_paths.each do |template|
119
+ Merb::AbstractController.add_path_to_template_cache(template)
120
+ end
121
+ end
122
+
123
+ def load_inline_helpers
124
+ partials = template_paths("_*.{erb,haml}")
125
+
126
+ partials.each do |partial|
127
+ case partial
128
+ when /erb$/
129
+ template = Erubis::Eruby.new(File.read(partial))
130
+ template.def_method(Merb::GlobalHelper, partial.gsub(/[^\.a-zA-Z0-9]/, "__").gsub(/\./, "_"), partial)
131
+ when /haml$/
132
+ if Object.const_defined?(:Haml) and Haml::Engine.instance_methods.include?('def_method')
133
+ template = Haml::Engine.new(File.read(partial), :filename => partial)
134
+ template.def_method(Merb::GlobalHelper, partial.gsub(/[^\.a-zA-Z0-9]/, "__").gsub(/\./, "_"))
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ def load_application
141
+ $LOAD_PATH.unshift( File.join(Merb.root , '/app/models') )
142
+ $LOAD_PATH.unshift( File.join(Merb.root , '/app/controllers') )
143
+ $LOAD_PATH.unshift( File.join(Merb.root , '/lib') )
144
+ Merb.load_paths.each do |glob|
145
+ Dir[Merb.root + glob].each { |m| require m }
146
+ end
147
+ load_action_arguments
148
+ load_controller_template_path_cache
149
+ load_inline_helpers
150
+ @app_loaded = true
151
+ (@after_app_blocks || []).each { |b| b.call }
152
+ require "sass/plugin" if File.directory?(Merb.root / "public" / "stylesheets" / "sass")
153
+ end
154
+
155
+ def remove_constant(const)
156
+ parts = const.to_s.split("::")
157
+ base = parts.size == 1 ? Object : Object.full_const_get(parts[0..-2].join("::"))
158
+ object = parts[-1].intern
159
+ Merb.logger.info("Removing constant #{object} from #{base}")
160
+ base.send(:remove_const, object) if object
161
+ Merb::Controller._subclasses.delete(const)
162
+ end
163
+
164
+ def reload
165
+ return if !Merb::Config[:reloader] || !Object.const_defined?(:MERB_PATHS)
166
+
167
+ # First we collect all files in the project (this will also grab newly added files)
168
+ project_files = MERB_PATHS.map { |path| Dir[Merb.root + path] }.flatten.uniq
169
+ partials = template_paths("_*.*").map { |path| Dir[path] }.flatten.uniq
170
+ project_mtime = max_mtime(project_files + partials) # Latest changed time of all project files
171
+
172
+ return if @mtime.nil? || @mtime >= project_mtime # Only continue if a file has changed
173
+
174
+ project_files.each do |file|
175
+ if File.mtime(file) >= @mtime
176
+ # If the file has changed or been added since the last project reload time
177
+ # remove any cannonical constants, based on what type of project file it is
178
+ # and then reload the file
179
+ begin
180
+ constant = case file
181
+ when %r[/app/(models|controllers|parts|mailers)/(.+)\.rb$]
182
+ $2.to_const_string
183
+ when %r[/app/(helpers)/(.+)\.rb$]
184
+ "Merb::" + $2.to_const_string
185
+ end
186
+ remove_constant(constant)
187
+ rescue NameError => e
188
+ Merb.logger.warn "Couldn't remove constant #{constant}"
189
+ end
190
+
191
+ begin
192
+ Merb.logger.info("Reloading file #{file}")
193
+ old_subclasses = Merb::Controller._subclasses.dup
194
+ load(file)
195
+ loaded_classes = Merb::Controller._subclasses - old_subclasses
196
+ load_action_arguments(loaded_classes)
197
+ rescue Exception => e
198
+ puts "Error reloading file #{file}: #{e}"
199
+ Merb.logger.warn " Error: #{e}"
200
+ end
201
+
202
+ # constant = file =~ /\/(controllers|models|mailers|helpers|parts)\/(.*).rb/ ? $2.to_const_string : nil
203
+ # remove_constant($2.to_const_string, ($1 == "helpers") ? Merb : nil)
204
+ # load file and puts "loaded file: #{file}"
205
+ end
206
+ end
207
+
208
+ # Rebuild the glob cache and erubis inline helpers
209
+ load_controller_template_path_cache
210
+ load_inline_helpers
211
+
212
+ @mtime = project_mtime # As the last action, update the current @mtime
213
+ end
214
+
215
+ end # class << self
216
+ end # BootLoader
217
+ end # Merb
@@ -1,4 +1,4 @@
1
- corelib = __DIR__+'/merb/caching'
1
+ corelib = Merb.framework_root + '/merb/caching'
2
2
 
3
3
  %w[ action_cache
4
4
  fragment_cache
@@ -62,7 +62,7 @@ module Merb
62
62
  private
63
63
 
64
64
  def _caching_enabled?
65
- ::Merb::Server.config[:cache_templates]
65
+ ::Merb::Config[:cache_templates]
66
66
  end
67
67
 
68
68
  def _get_action_fragment
@@ -25,7 +25,7 @@ module Merb
25
25
  end
26
26
 
27
27
  def determine_cache_store
28
- if ::Merb::Server.config[:cache_store].to_s == "file"
28
+ if ::Merb::Config[:cache_store].to_s == "file"
29
29
  require 'merb/caching/store/file_cache'
30
30
  ::Merb::Caching::Store::FileCache.new
31
31
  else
@@ -9,7 +9,7 @@ module Merb
9
9
  class FileCache
10
10
 
11
11
  def initialize(name = "cache", keepalive = nil)
12
- @path = File.join(MERB_ROOT, name)
12
+ @path = File.join(Merb.root, name)
13
13
  @keepalive = keepalive
14
14
  end
15
15
 
@@ -0,0 +1,290 @@
1
+ require File.join(File.dirname(__FILE__), 'erubis_ext')
2
+ require File.join(File.dirname(__FILE__), 'version')
3
+ require File.join(File.dirname(__FILE__), 'boot_loader')
4
+ module Merb
5
+ class Config
6
+ class << self
7
+
8
+ def defaults
9
+ @defaults ||= {
10
+ :host => "0.0.0.0",
11
+ :port => "4000",
12
+ :reloader => true,
13
+ :cache_templates => false,
14
+ :merb_root => Dir.pwd,
15
+ :use_mutex => true,
16
+ :session_id_cookie_only => true,
17
+ :query_string_whitelist => [],
18
+ :mongrel_x_sendfile => true
19
+ }
20
+ end
21
+
22
+ def [](key)
23
+ (@configuration||{})[key]
24
+ end
25
+
26
+ def []=(key,val)
27
+ @configuration[key] = val
28
+ end
29
+ def delete(key)
30
+ @configuration.delete key
31
+ end
32
+
33
+ def fetch(key, default)
34
+ @configuration.fetch key, default
35
+ end
36
+
37
+ def to_yaml
38
+ @configuration.to_yaml
39
+ end
40
+
41
+ def setup(global_merb_yml = nil)
42
+ @configuration ||= {}
43
+ if FileTest.exist? "#{defaults[:merb_root]}/framework"
44
+ $LOAD_PATH.unshift( "#{defaults[:merb_root]}/framework" )
45
+ end
46
+ global_merb_yml ||= "#{defaults[:merb_root]}/config/merb.yml"
47
+ apply_configuration_from_file defaults, global_merb_yml
48
+ end
49
+
50
+ def apply_configuration_from_file(configuration, file)
51
+ if File.exists?(file)
52
+ configuration.merge(Erubis.load_yaml_file(file))
53
+ else
54
+ configuration
55
+ end
56
+ end
57
+
58
+ def parse_args(argv = ARGV)
59
+ @configuration ||= {}
60
+ # Our primary configuration hash for the length of this method
61
+ options = {}
62
+
63
+ # Environment variables always win
64
+ options[:environment] = ENV['MERB_ENV'] if ENV['MERB_ENV']
65
+
66
+ # Build a parser for the command line arguments
67
+ opts = OptionParser.new do |opts|
68
+ opts.version = Merb::VERSION
69
+ opts.release = Merb::RELEASE
70
+
71
+ opts.banner = "Usage: merb [fdcepghmisluMG] [argument]"
72
+ opts.define_head "Merb Mongrel+ Erb. Lightweight replacement for ActionPack."
73
+ opts.separator '*'*80
74
+ opts.separator 'If no flags are given, Merb starts in the foreground on port 4000.'
75
+ opts.separator '*'*80
76
+
77
+ opts.on("-u", "--user USER", "This flag is for having merb run as a user other than the one currently logged in. Note: if you set this you must also provide a --group option for it to take effect.") do |config|
78
+ options[:user] = config
79
+ end
80
+
81
+ opts.on("-G", "--group GROUP", "This flag is for having merb run as a group other than the one currently logged in. Note: if you set this you must also provide a --user option for it to take effect.") do |config|
82
+ options[:group] = config
83
+ end
84
+
85
+ opts.on("-f", "--config-file FILENAME", "This flag is for adding extra config files for things like the upload progress module.") do |config|
86
+ options[:config] = config
87
+ end
88
+
89
+ opts.on("-d", "--daemonize", "This will run a single merb in the background.") do |config|
90
+ options[:daemonize] = true
91
+ end
92
+
93
+ opts.on("-c", "--cluster-nodes NUM_MERBS", "Number of merb daemons to run.") do |nodes|
94
+ options[:cluster] = nodes
95
+ end
96
+
97
+ opts.on("-p", "--port PORTNUM", "Port to run merb on, defaults to 4000.") do |port|
98
+ options[:port] = port
99
+ end
100
+
101
+ opts.on("-h", "--host HOSTNAME", "Host to bind to (default is all IP's).") do |host|
102
+ options[:host] = host
103
+ end
104
+
105
+ opts.on("-m", "--merb-root Merb.root", "The path to the Merb.root for the app you want to run (default is current working dir).") do |Merb.root|
106
+ options[:merb_root] = File.expand_path(Merb.root)
107
+ end
108
+
109
+ opts.on("-i", "--irb-console", "This flag will start merb in irb console mode. All your models and other classes will be available for you in an irb session.") do |console|
110
+ ::Merb::BootLoader.initialize_merb
111
+ _merb = Class.new do
112
+ class << self
113
+ include Merb::GeneralControllerMixin
114
+ def params() {} end
115
+ end
116
+ def self.show_routes(all_opts = false)
117
+ seen = []
118
+ unless Merb::Router.named_routes.empty?
119
+ puts "Named Routes"
120
+ Merb::Router.named_routes.each do |name,route|
121
+ puts " #{name}: #{route}"
122
+ seen << route
123
+ end
124
+ end
125
+ puts "Anonymous Routes"
126
+ (Merb::Router.routes - seen).each do |route|
127
+ puts " #{route}"
128
+ end
129
+ nil
130
+ end
131
+ end
132
+
133
+ Object.send(:define_method, :merb) {
134
+ _merb
135
+ }
136
+ ARGV.clear # Avoid passing args to IRB
137
+ require 'irb'
138
+ require 'irb/completion'
139
+ def exit
140
+ exit!
141
+ end
142
+ if File.exists? ".irbrc"
143
+ ENV['IRBRC'] = ".irbrc"
144
+ end
145
+ IRB.start
146
+ exit!
147
+ end
148
+
149
+ opts.on("-s", "--start-drb PORTNUM", "This is the port number to run the drb daemon on for sessions and upload progress monitoring.") do |drb_port|
150
+ puts "Starting merb drb server on port: #{Merb::Config[:drb_server_port]}"
151
+ Merb::Server.start(drb_port, :drbserver_start)
152
+ exit if Merb::Config[:only_drb]
153
+ end
154
+
155
+ opts.on("-l", "--log-level LEVEL", "Log levels can be set to any of these options: DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN") do |loglevel|
156
+ options[:log_level] = loglevel
157
+ end
158
+
159
+ opts.on("-e", "--environment STRING", "Run merb in the correct mode(development, production, testing)") do |env|
160
+ options[:environment] ||= env
161
+ end
162
+
163
+ opts.on("-r", "--script-runner ['RUBY CODE'| FULL_SCRIPT_PATH]",
164
+ "Command-line option to run scripts and/or code in the merb app.") do |code_or_file|
165
+ ::Merb::BootLoader.initialize_merb
166
+ if File.exists?(code_or_file)
167
+ eval(File.read(code_or_file))
168
+ else
169
+ eval(code_or_file)
170
+ end
171
+ exit!
172
+ end
173
+
174
+ opts.on("-P","--generate-plugin PATH", "Generate a fresh merb plugin at PATH.") do |path|
175
+ require 'merb/generators/merb_plugin'
176
+ ::Merb::PluginGenerator.run path || Dir.pwd
177
+ exit
178
+ end
179
+
180
+ opts.on("-K", "--graceful PORT or all", "Gracefully kill one merb proceses by port number. Use merb -K all to gracefully kill all merbs.") do |ports|
181
+ @configuration = defaults.merge(options)
182
+ Merb::Server.kill(ports, 1)
183
+ end
184
+
185
+ opts.on("-k", "--kill PORT or all", "Kill one merb proceses by port number. Use merb -k all to kill all merbs.") do |ports|
186
+ @configuration = defaults.merge(options)
187
+ Merb::Server.kill(ports, 9)
188
+ end
189
+
190
+ opts.on("-M", "--merb-config FILENAME", "This flag is for explicitly declaring the merb app's config file.") do |config|
191
+ options[:merb_config] = config
192
+ end
193
+
194
+ opts.on("-w", "--webrick", "Run merb using Webrick Rack Adapter instead of mongrel.") do |webport|
195
+ puts "Starting merb webrick server on port: #{Merb::Config[:port]}"
196
+ trap('TERM') { exit }
197
+ Merb::Server.webrick_start(Merb::Config[:port])
198
+ end
199
+
200
+ opts.on("-F", "--fastcgi", "Run merb using FastCGI Rack Adapter instead of mongrel.") do
201
+ trap('TERM') { exit }
202
+ Merb::Server.fastcgi_start
203
+ end
204
+
205
+ opts.on("-X", "--mutex on/off", "This flag is for turning the mutex lock on and off.") do |mutex|
206
+ if mutex == 'off'
207
+ options[:use_mutex] = false
208
+ else
209
+ options[:use_mutex] = true
210
+ end
211
+ end
212
+
213
+ opts.on("-D", "--debugger", "Run merb using rDebug.") do
214
+ begin
215
+ require 'ruby-debug'
216
+ Debugger.start
217
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
218
+ puts "Debugger enabled"
219
+ rescue LoadError
220
+ puts "You need to install ruby-debug to run the server in debugging mode. With gems, use 'gem install ruby-debug'"
221
+ exit
222
+ end
223
+ end
224
+
225
+ opts.on("-?", "-H", "--help", "Show this help message") do
226
+ puts opts
227
+ exit
228
+ end
229
+ end
230
+
231
+ # If we run merb with no arguments and we are not inside a merb root
232
+ # show the help message
233
+ if !defined?(Merb.framework_root) && (argv.size == 0) && !File.exists?("#{options[:merb_root] || Merb::Config.defaults[:merb_root]}/config/merb_init.rb")
234
+ puts "You are not in the root of a merb application...\n"
235
+ puts opts
236
+ exit
237
+ end
238
+
239
+ # Parse what we have on the command line
240
+ opts.parse!(argv)
241
+
242
+ # merb <argument> is same as merb -g <argument>
243
+ if argv.size == 1
244
+ require 'merb/generators/merb_app/merb_app'
245
+ ::Merb::AppGenerator.run File.expand_path(argv.last)
246
+ exit!
247
+ end
248
+
249
+ # Load up the configuration from file, but keep the command line
250
+ # options that may have been chosen. Also, pass-through if we have
251
+ # a new merb_config path.
252
+ options = Merb::Config.setup(options[:merb_config]).merge(options)
253
+
254
+ # Finally, if all else fails... set the environment to 'development'
255
+ options[:environment] ||= 'development'
256
+
257
+ environment_merb_yml = "#{options[:merb_root]}/config/environments/#{options[:environment]}.yml"
258
+
259
+ @configuration = Merb::Config.apply_configuration_from_file options, environment_merb_yml
260
+
261
+ case Merb::Config[:environment].to_s
262
+ when 'production'
263
+ Merb::Config[:reloader] = Merb::Config.fetch(:reloader, false)
264
+ Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, false)
265
+ Merb::Config[:cache_templates] = true
266
+ else
267
+ Merb::Config[:reloader] = Merb::Config.fetch(:reloader, true)
268
+ Merb::Config[:exception_details] = Merb::Config.fetch(:exception_details, true)
269
+ end
270
+
271
+ Merb::Config[:reloader_time] ||= 0.5 if Merb::Config[:reloader] == true
272
+
273
+
274
+ if Merb::Config[:reloader]
275
+ Thread.abort_on_exception = true
276
+ Thread.new do
277
+ loop do
278
+ sleep( Merb::Config[:reloader_time] )
279
+ ::Merb::BootLoader.reload if ::Merb::BootLoader.app_loaded?
280
+ end
281
+ Thread.exit
282
+ end
283
+ end
284
+ @configuration
285
+ end
286
+
287
+ end # class << self
288
+ end # Config
289
+
290
+ end