padrino-core 0.7.5 → 0.7.6

Sign up to get free protection for your applications and to get access to all the features.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.5
1
+ 0.7.6
@@ -8,7 +8,7 @@ module Padrino
8
8
  class Application < Sinatra::Application
9
9
 
10
10
  class << self
11
- def inherited(subclass)
11
+ def inherited(subclass) #:nodoc:
12
12
  CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
13
13
  subclass.default_configuration!
14
14
  Padrino.set_load_paths File.join(subclass.root, "/models")
@@ -70,7 +70,7 @@ module Padrino
70
70
  ##
71
71
  # Usher router, for fatures and configurations see: http://github.com/joshbuddy/usher
72
72
  #
73
- # Examples:
73
+ # ==== Examples
74
74
  #
75
75
  # router.add_route('/greedy/{!:greed,.*}')
76
76
  # router.recognize_path('/simple')
@@ -86,6 +86,8 @@ module Padrino
86
86
  ##
87
87
  # Instance method for url generation like:
88
88
  #
89
+ # ==== Examples
90
+ #
89
91
  # url(:show, :id => 1)
90
92
  # url(:show, :name => :test)
91
93
  # url("/show/:id/:name", :id => 1, :name => foo)
@@ -120,6 +122,12 @@ module Padrino
120
122
  ##
121
123
  # Reloads the application files from all defined load paths
122
124
  #
125
+ # This method is used from our Padrino Reloader.
126
+ #
127
+ # ==== Examples
128
+ #
129
+ # MyApp.reload!
130
+ #
123
131
  def reload!
124
132
  reset_routes! # remove all existing user-defined application routes
125
133
  Padrino.load_dependency(self.app_file) # reload the app file
@@ -129,6 +137,10 @@ module Padrino
129
137
  ##
130
138
  # Resets application routes to only routes not defined by the user
131
139
  #
140
+ # ==== Examples
141
+ #
142
+ # MyApp.reset_routes!
143
+ #
132
144
  def reset_routes!
133
145
  router.reset!
134
146
  default_routes!
@@ -229,9 +241,9 @@ module Padrino
229
241
  # Requires the middleware and initializer modules to configure components
230
242
  #
231
243
  def register_initializers
232
- use Padrino::RackLogger
233
- use Padrino::Reloader if reload?
234
- use Rack::Flash if flash?
244
+ use Padrino::Logger::Rack
245
+ use Padrino::Reloader::Rack if reload?
246
+ use Rack::Flash if flash?
235
247
  @initializer_path ||= Padrino.root + '/config/initializers/*.rb'
236
248
  Dir[@initializer_path].each { |file| register_initializer(file) }
237
249
  end
@@ -242,7 +254,7 @@ module Padrino
242
254
  def register_framework_extensions
243
255
  register Padrino::Mailer if padrino_mailer?
244
256
  register Padrino::Helpers if padrino_helpers?
245
- register Padrino::AccessControl if authentication?
257
+ register Padrino::Admin::AccessControl if authentication?
246
258
  end
247
259
 
248
260
  ##
@@ -284,6 +296,8 @@ module Padrino
284
296
  ##
285
297
  # Rewrite default because now routes can be:
286
298
  #
299
+ # ==== Examples
300
+ #
287
301
  # get :index # => "/"
288
302
  # get :index, :map => "/" # => "/"
289
303
  # get :show, :map => "/show-me" # => "/show-me"
@@ -384,6 +398,8 @@ module Padrino
384
398
  ##
385
399
  # Return the request format, this is useful when we need to respond to a given content_type like:
386
400
  #
401
+ # ==== Examples
402
+ #
387
403
  # get :index, :respond_to => :any do
388
404
  # case content_type
389
405
  # when :js then ...
@@ -399,6 +415,8 @@ module Padrino
399
415
  ##
400
416
  # Instance method for url generation like:
401
417
  #
418
+ # ==== Examples
419
+ #
402
420
  # url(:show, :id => 1)
403
421
  # url(:show, :name => :test)
404
422
  # url("/show/:id/:name", :id => 1, :name => foo)
@@ -470,6 +488,8 @@ module Padrino
470
488
  ##
471
489
  # When we set :auto_locale, true then if we use param locale like:
472
490
  #
491
+ # ==== Examples
492
+ #
473
493
  # get "/:locale/some/foo" do; ...; end
474
494
  #
475
495
  # we automatically set the I18n locale to params[:locale]
@@ -36,12 +36,9 @@ module Padrino
36
36
  # line / method information; the resulting array contains filenames only.
37
37
  #
38
38
  def self.caller_files
39
- caller_locations.map { |file,line| file }
40
- end
41
-
42
- def self.caller_locations
43
39
  caller(1).
44
40
  map { |line| line.split(/:(?=\d|in )/)[0,2] }.
45
- reject { |file,line| PADRINO_IGNORE_CALLERS.any? { |pattern| file =~ pattern } }
41
+ reject { |file,line| PADRINO_IGNORE_CALLERS.any? { |pattern| file =~ pattern } }.
42
+ map { |file,line| file }
46
43
  end
47
44
  end # Padrino
@@ -11,7 +11,7 @@ module Padrino
11
11
  require_dependencies("#{root}/lib/**/*.rb", "#{root}/shared/lib/**/*.rb") # load root libs
12
12
  require_dependencies("#{root}/models/**/*.rb", "#{root}/shared/models/**/*.rb") # load root models
13
13
  require_dependencies("#{root}/config/database.rb", "#{root}/config/apps.rb") # load configuration
14
- Stat.reload! # We need to fill our Stat::CACHE but we do that only for development
14
+ Reloader::Stat.reload! # We need to fill our Stat::CACHE but we do that only for development
15
15
  Thread.current[:padrino_loaded] = true
16
16
  end
17
17
 
@@ -19,8 +19,8 @@ module Padrino
19
19
  # Method for reloading required applications and their files
20
20
  #
21
21
  def reload!
22
- return unless Stat.changed?
23
- Stat.reload! # detects the modified files
22
+ return unless Reloader::Stat.changed?
23
+ Reloader::Stat.reload! # detects the modified files
24
24
  Padrino.mounted_apps.each { |m| m.app_object.reload! } # finally we reload all files for each app
25
25
  end
26
26
 
@@ -55,7 +55,7 @@ module Padrino
55
55
  #
56
56
  # With +require_dependencies+ we don't have this problem.
57
57
  #
58
- # Example:
58
+ # ==== Examples
59
59
  # # For require all our app libs we need to do:
60
60
  # require_dependencies("#{Padrino.root}/lib/**/*.rb")
61
61
  #
@@ -6,7 +6,7 @@ module Padrino
6
6
  ##
7
7
  # Returns the padrino logger
8
8
  #
9
- # Examples:
9
+ # ==== Examples
10
10
  #
11
11
  # logger.debug "foo"
12
12
  # logger.warn "bar"
@@ -15,6 +15,14 @@ module Padrino
15
15
  Thread.current[:padrino_logger] ||= Padrino::Logger.setup!
16
16
  end
17
17
 
18
+ ##
19
+ # Extensions to the built in Ruby logger.
20
+ #
21
+ # ==== Examples
22
+ #
23
+ # logger.debug "foo"
24
+ # logger.warn "bar"
25
+ #
18
26
  class Logger
19
27
 
20
28
  attr_accessor :level
@@ -31,6 +39,7 @@ module Padrino
31
39
  # :warn:: A warning
32
40
  # :info:: generic (useful) information about system operation
33
41
  # :debug:: low-level information for developers
42
+ #
34
43
  Levels = {
35
44
  :fatal => 7,
36
45
  :error => 6,
@@ -55,7 +64,7 @@ module Padrino
55
64
  # :format_datetime:: Format of datetime. Defaults to: "%d/%b/%Y %H:%M:%S"
56
65
  # :format_message:: Format of message. Defaults to: ""%s - - [%s] \"%s\"""
57
66
  #
58
- # Example:
67
+ # ==== Examples
59
68
  #
60
69
  # Padrino::Logger::Config[:development] = { :log_level => :debug, :to_file }
61
70
  # # or you can edit our defaults
@@ -98,7 +107,7 @@ module Padrino
98
107
  ##
99
108
  # To initialize the logger you create a new object, proxies to set_log.
100
109
  #
101
- # ==== Options can be:
110
+ # ==== Options
102
111
  #
103
112
  # :stream:: Either an IO object or a name of a logfile. Defaults to $stdout
104
113
  # :log_level::
@@ -109,6 +118,7 @@ module Padrino
109
118
  # added. Defaults to true.
110
119
  # :format_datetime:: Format of datetime. Defaults to: "%d/%b/%Y %H:%M:%S"
111
120
  # :format_message:: Format of message. Defaults to: ""%s - - [%s] \"%s\"""
121
+ #
112
122
  def initialize(options={})
113
123
  @buffer = []
114
124
  @auto_flush = options.has_key?(:auto_flush) ? options[:auto_flush] : true
@@ -147,6 +157,9 @@ module Padrino
147
157
  self << @format_message % [level.to_s.upcase, Time.now.strftime(@format_datetime), message.to_s]
148
158
  end
149
159
 
160
+ ##
161
+ # Directly append message to the log.
162
+ #
150
163
  def <<(message = nil)
151
164
  message << "\n" unless message[-1] == ?\n
152
165
  @buffer << message
@@ -202,63 +215,60 @@ module Padrino
202
215
  LEVELMETHODS
203
216
  end
204
217
 
205
- end
206
-
207
- ##
208
- # RackLogger forwards every request to an +app+ given, and
209
- # logs a line in the Apache common log format to the +logger+, or
210
- # rack.errors by default.
211
- #
212
- class RackLogger
213
218
  ##
214
- # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
215
- # "lilith.local - - GET / HTTP/1.1 500 -"
216
- # %{%s - %s %s %s%s %s - %d %s %0.4f}
219
+ # Padrino::Loggger::Rack forwards every request to an +app+ given, and
220
+ # logs a line in the Apache common log format to the +logger+, or
221
+ # rack.errors by default.
217
222
  #
218
- FORMAT = %{%s - %s %s %s%s %s - %d %s %0.4f}
219
-
220
- def initialize(app)
221
- @app = app
222
- end
223
+ class Rack
224
+ ##
225
+ # Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
226
+ # "lilith.local - - GET / HTTP/1.1 500 -"
227
+ # %{%s - %s %s %s%s %s - %d %s %0.4f}
228
+ #
229
+ FORMAT = %{%s - %s %s %s%s %s - %d %s %0.4f}
223
230
 
224
- def call(env)
225
- began_at = Time.now
226
- status, header, body = @app.call(env)
227
- log(env, status, header, began_at)
228
- [status, header, body]
229
- end
231
+ def initialize(app)
232
+ @app = app
233
+ end
230
234
 
231
- private
235
+ def call(env)
236
+ began_at = Time.now
237
+ status, header, body = @app.call(env)
238
+ log(env, status, header, began_at)
239
+ [status, header, body]
240
+ end
232
241
 
233
- def log(env, status, header, began_at)
234
- now = Time.now
235
- length = extract_content_length(header)
242
+ private
243
+ def log(env, status, header, began_at)
244
+ now = Time.now
245
+ length = extract_content_length(header)
236
246
 
237
- logger.debug FORMAT % [
238
- env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
239
- env["REMOTE_USER"] || "-",
240
- env["REQUEST_METHOD"],
241
- env["PATH_INFO"],
242
- env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
243
- env["HTTP_VERSION"],
244
- status.to_s[0..3],
245
- length,
246
- now - began_at ]
247
- end
247
+ logger.debug FORMAT % [
248
+ env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
249
+ env["REMOTE_USER"] || "-",
250
+ env["REQUEST_METHOD"],
251
+ env["PATH_INFO"],
252
+ env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
253
+ env["HTTP_VERSION"],
254
+ status.to_s[0..3],
255
+ length,
256
+ now - began_at ]
257
+ end
248
258
 
249
- def extract_content_length(headers)
250
- headers.each do |key, value|
251
- if key.downcase == 'content-length'
252
- return value.to_s == '0' ? '-' : value
259
+ def extract_content_length(headers)
260
+ headers.each do |key, value|
261
+ if key.downcase == 'content-length'
262
+ return value.to_s == '0' ? '-' : value
263
+ end
264
+ end
265
+ '-'
253
266
  end
254
- end
255
- '-'
256
- end
267
+ end # Rack
257
268
  end # Logger
258
269
  end # Padrino
259
270
 
260
271
  module Kernel #:nodoc:
261
-
262
272
  ##
263
273
  # Define a logger available every where in our app
264
274
  #
@@ -3,7 +3,7 @@ module Padrino
3
3
  # Represents a particular mounted padrino application
4
4
  # Stores the name of the application (app folder name) and url mount path
5
5
  #
6
- # Example:
6
+ # ==== Examples
7
7
  #
8
8
  # Mounter.new("blog_app", :app_class => "Blog").to("/blog")
9
9
  # Mounter.new("blog_app", :app_file => "/path/to/blog/app.rb").to("/blog")
@@ -22,7 +22,8 @@ module Padrino
22
22
  ##
23
23
  # Registers the mounted application onto Padrino
24
24
  #
25
- # Example:
25
+ # ==== Examples
26
+ #
26
27
  # Mounter.new("blog_app").to("/blog")
27
28
  #
28
29
  def to(mount_url)
@@ -102,7 +103,7 @@ module Padrino
102
103
  ##
103
104
  # Mounts the core application onto Padrino project with given app settings (file, class, root)
104
105
  #
105
- # Examples:
106
+ # ==== Examples
106
107
  #
107
108
  # Padrino.mount_core("Blog")
108
109
  # Padrino.mount_core(:app_file => "/path/to/file", :app_class => "Blog")
@@ -1,33 +1,124 @@
1
+ require 'pathname'
2
+
1
3
  module Padrino
2
4
  ##
3
5
  # High performant source reloader
4
6
  #
5
- # This class acts as Rack middleware.
6
- #
7
- # It is performing a check/reload cycle at the start of every request, but
8
- # also respects a cool down time, during which nothing will be done.
9
- #
10
- class Reloader
11
-
12
- def initialize(app, cooldown = 1)
13
- @app = app
14
- @cooldown = cooldown
15
- @last = (Time.now - cooldown)
16
- end
7
+ module Reloader
8
+ ##
9
+ # This class acts as Rack middleware.
10
+ #
11
+ # It is performing a check/reload cycle at the start of every request, but
12
+ # also respects a cool down time, during which nothing will be done.
13
+ #
14
+ class Rack
15
+ def initialize(app, cooldown = 1)
16
+ @app = app
17
+ @cooldown = cooldown
18
+ @last = (Time.now - cooldown)
19
+ end
20
+
21
+ def call(env)
22
+ if @cooldown and Time.now > @last + @cooldown
23
+ if Thread.list.size > 1
24
+ Thread.exclusive { Padrino.reload! }
25
+ else
26
+ Padrino.reload!
27
+ end
17
28
 
18
- def call(env)
19
- if @cooldown and Time.now > @last + @cooldown
20
- if Thread.list.size > 1
21
- Thread.exclusive { Padrino.reload! }
22
- else
23
- Padrino.reload!
29
+ @last = Time.now
24
30
  end
25
31
 
26
- @last = Time.now
32
+ @app.call(env)
27
33
  end
28
-
29
- @app.call(env)
30
34
  end
35
+
36
+ ##
37
+ # What makes it especially suited for use in a any environment is that
38
+ # any file will only be checked once and there will only be made one system
39
+ # call stat(2).
40
+ #
41
+ # Please note that this will not reload files in the background, it does so
42
+ # only when actively called.
43
+ #
44
+ module Stat
45
+ class << self
46
+ CACHE = {}
47
+ MTIMES = {}
48
+
49
+ def reload!
50
+ rotation do |file, mtime|
51
+ previous_mtime = MTIMES[file] ||= mtime
52
+ safe_load(file, mtime) if mtime > previous_mtime
53
+ end
54
+ end
55
+
56
+ def changed?
57
+ changed = false
58
+ rotation do |file, mtime|
59
+ previous_mtime = MTIMES[file] ||= mtime
60
+ changed = true if mtime > MTIMES[file]
61
+ end
62
+ changed
63
+ end
64
+
65
+ ##
66
+ # A safe Kernel::load, issuing the hooks depending on the results
67
+ #
68
+ def safe_load(file, mtime)
69
+ logger.debug "Reloading #{file}"
70
+ load(file)
71
+ file
72
+ rescue LoadError, SyntaxError => ex
73
+ logger.error ex
74
+ ensure
75
+ MTIMES[file] = mtime
76
+ end
77
+
78
+ def rotation
79
+ files = [$0, *$LOADED_FEATURES].uniq
80
+ paths = ['./', *$:].uniq
81
+
82
+ files.map{ |file|
83
+ next if file =~ /\.(so|bundle)$/ # cannot reload compiled files
84
+ found, stat = figure_path(file, paths)
85
+ next unless found && stat && mtime = stat.mtime
86
+
87
+ CACHE[file] = found
88
+
89
+ yield(found, mtime)
90
+ }.compact
91
+ end
92
+
93
+ ##
94
+ # Takes a relative or absolute +file+ name, a couple possible +paths+ that
95
+ # the +file+ might reside in. Returns the full path and File::Stat for the
96
+ # path.
97
+ #
98
+ def figure_path(file, paths)
99
+ found = CACHE[file]
100
+ found = file if !found and Pathname.new(file).absolute?
101
+ found, stat = safe_stat(found)
102
+ return found, stat if found
103
+
104
+ paths.find do |possible_path|
105
+ path = ::File.join(possible_path, file)
106
+ found, stat = safe_stat(path)
107
+ return ::File.expand_path(found), stat if found
108
+ end
109
+
110
+ return false, false
111
+ end
112
+
113
+ def safe_stat(file)
114
+ return unless file
115
+ stat = ::File.stat(file)
116
+ return file, stat if stat.file?
117
+ rescue Errno::ENOENT, Errno::ENOTDIR
118
+ CACHE.delete(file) and false
119
+ end
120
+ end # self
121
+ end # Stat
31
122
  end # Reloader
32
123
  end # Padrino
33
124
 
@@ -4,7 +4,7 @@ module Padrino
4
4
  # Run the Padrino apps as a self-hosted server using:
5
5
  # thin, mongrel, webrick in that order.
6
6
  #
7
- # Examples:
7
+ # ==== Examples
8
8
  #
9
9
  # Padrino.run! # with these defaults => host: "localhost", port: "3000", adapter: the first found
10
10
  # Padrino.run!("localhost", "4000", "mongrel") # use => host: "localhost", port: "3000", adapter: "mongrel"
@@ -1,6 +1,8 @@
1
1
  # This requires necessary pieces of ActiveSupport for the dependencies required by Padrino
2
2
 
3
- ## ActiveSupport::Deprecation
3
+ ## ActiveSupport#Version
4
+ require 'active_support/version'
5
+ ## ActiveSupport#Deprecation
4
6
  unless defined?(ActiveSupport::Deprecation)
5
7
  require 'active_support/core_ext/kernel' unless Kernel.method_defined?(:silence_warnings)
6
8
  require 'active_support/core_ext/module' unless Module.method_defined?(:mattr_accessor)
@@ -24,8 +26,11 @@ require 'active_support/core_ext/blank' unless Object.method_defined?(:blank?)
24
26
  require 'active_support/core_ext/array' unless Array.method_defined?(:extract_options!)
25
27
  ## Module#alias_method_chain
26
28
  require 'active_support/core_ext/module' unless Module.method_defined?(:alias_method_chain)
27
- ## SupportLite::OrderedHash
29
+ ## SupportLite#OrderedHash
28
30
  require 'active_support/ordered_hash' unless defined?(ActiveSupport::OrderedHash)
31
+ ## Float#round
32
+ require 'active_support/core_ext/float/rounding'
33
+
29
34
  unless defined?(SupportLite::OrderedHash)
30
35
  module SupportLite
31
36
  OrderedHash = ::ActiveSupport::OrderedHash
@@ -182,3 +182,26 @@ unless Module.method_defined?(:alias_method_chain)
182
182
  end
183
183
  end
184
184
  end
185
+
186
+ ## Float#round
187
+ unless Float.method_defined?(:round)
188
+ class Float
189
+ alias precisionless_round round
190
+ private :precisionless_round
191
+
192
+ # Rounds the float with the specified precision.
193
+ #
194
+ # x = 1.337
195
+ # x.round # => 1
196
+ # x.round(1) # => 1.3
197
+ # x.round(2) # => 1.34
198
+ def round(precision = nil)
199
+ if precision
200
+ magnitude = 10.0 ** precision
201
+ (self * magnitude).round / magnitude
202
+ else
203
+ precisionless_round
204
+ end
205
+ end
206
+ end
207
+ end
@@ -5,7 +5,11 @@ module Padrino
5
5
  # thirdy party tasks, in your gem/plugin/extension you
6
6
  # need only do this:
7
7
  #
8
+ # ==== Examples
9
+ #
8
10
  # Padrino::Tasks.files << yourtask.rb
11
+ # Padrino::Tasks.files.concat(Dir["/path/to/all/my/tasks/*.rb"])
12
+ # Padrino::Tasks.files.unshift("yourtask.rb")
9
13
  #
10
14
  module Tasks
11
15
 
data/lib/padrino-core.rb CHANGED
@@ -13,7 +13,7 @@ module Padrino
13
13
  ##
14
14
  # Helper method for file references.
15
15
  #
16
- # Example:
16
+ # ==== Examples
17
17
  # # Referencing a file in config called settings.yml
18
18
  # Padrino.root("config", "settings.yml")
19
19
  # # returns PADRINO_ROOT + "/config/setting.yml"
data/padrino-core.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{padrino-core}
8
- s.version = "0.7.5"
8
+ s.version = "0.7.6"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Padrino Team", "Nathan Esquenazi", "Davide D'Agostino", "Arthur Chiu"]
12
- s.date = %q{2010-02-09}
12
+ s.date = %q{2010-02-10}
13
13
  s.default_executable = %q{padrino}
14
14
  s.description = %q{The Padrino core gem required for use of this framework}
15
15
  s.email = %q{padrinorb@gmail.com}
@@ -41,7 +41,6 @@ Gem::Specification.new do |s|
41
41
  "lib/padrino-core/mounter.rb",
42
42
  "lib/padrino-core/reloader.rb",
43
43
  "lib/padrino-core/server.rb",
44
- "lib/padrino-core/stat.rb",
45
44
  "lib/padrino-core/support_lite.rb",
46
45
  "lib/padrino-core/support_lite/as_support.rb",
47
46
  "lib/padrino-core/support_lite/extlib_support.rb",
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: padrino-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.5
4
+ version: 0.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Padrino Team
@@ -12,7 +12,7 @@ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
14
 
15
- date: 2010-02-09 00:00:00 +01:00
15
+ date: 2010-02-10 00:00:00 +01:00
16
16
  default_executable: padrino
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
@@ -137,7 +137,6 @@ files:
137
137
  - lib/padrino-core/mounter.rb
138
138
  - lib/padrino-core/reloader.rb
139
139
  - lib/padrino-core/server.rb
140
- - lib/padrino-core/stat.rb
141
140
  - lib/padrino-core/support_lite.rb
142
141
  - lib/padrino-core/support_lite/as_support.rb
143
142
  - lib/padrino-core/support_lite/extlib_support.rb
@@ -1,90 +0,0 @@
1
- require 'pathname'
2
-
3
- module Padrino
4
- ##
5
- # What makes it especially suited for use in a any environment is that
6
- # any file will only be checked once and there will only be made one system
7
- # call stat(2).
8
- #
9
- # Please note that this will not reload files in the background, it does so
10
- # only when actively called.
11
- #
12
- module Stat
13
- class << self
14
- CACHE = {}
15
- MTIMES = {}
16
-
17
- def reload!
18
- rotation do |file, mtime|
19
- previous_mtime = MTIMES[file] ||= mtime
20
- safe_load(file, mtime) if mtime > previous_mtime
21
- end
22
- end
23
-
24
- def changed?
25
- changed = false
26
- rotation do |file, mtime|
27
- previous_mtime = MTIMES[file] ||= mtime
28
- changed = true if mtime > MTIMES[file]
29
- end
30
- changed
31
- end
32
-
33
- ##
34
- # A safe Kernel::load, issuing the hooks depending on the results
35
- #
36
- def safe_load(file, mtime)
37
- logger.debug "Reloading #{file}"
38
- load(file)
39
- file
40
- rescue LoadError, SyntaxError => ex
41
- $stderr.puts ex
42
- ensure
43
- MTIMES[file] = mtime
44
- end
45
-
46
- def rotation
47
- files = [$0, *$LOADED_FEATURES].uniq
48
- paths = ['./', *$:].uniq
49
-
50
- files.map{ |file|
51
- next if file =~ /\.(so|bundle)$/ # cannot reload compiled files
52
- found, stat = figure_path(file, paths)
53
- next unless found && stat && mtime = stat.mtime
54
-
55
- CACHE[file] = found
56
-
57
- yield(found, mtime)
58
- }.compact
59
- end
60
-
61
- ##
62
- # Takes a relative or absolute +file+ name, a couple possible +paths+ that
63
- # the +file+ might reside in. Returns the full path and File::Stat for the
64
- # path.
65
- #
66
- def figure_path(file, paths)
67
- found = CACHE[file]
68
- found = file if !found and Pathname.new(file).absolute?
69
- found, stat = safe_stat(found)
70
- return found, stat if found
71
-
72
- paths.find do |possible_path|
73
- path = ::File.join(possible_path, file)
74
- found, stat = safe_stat(path)
75
- return ::File.expand_path(found), stat if found
76
- end
77
-
78
- return false, false
79
- end
80
-
81
- def safe_stat(file)
82
- return unless file
83
- stat = ::File.stat(file)
84
- return file, stat if stat.file?
85
- rescue Errno::ENOENT, Errno::ENOTDIR
86
- CACHE.delete(file) and false
87
- end
88
- end # self
89
- end # Stat
90
- end # Padrino