padrino-core 0.7.5 → 0.7.6

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.
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