padrino-core 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,11 +7,200 @@ To install the 'full-stack' padrino framework, simply grab the latest version fr
7
7
  $ sudo gem install padrino --source http://gemcutter.org
8
8
 
9
9
  This will install the necessary padrino gems to get you started.
10
- Now you are ready to use this gem to enhance your sinatra projects or to create new Padrino applications.
10
+ Now you are ready to use this gem to enhance your existing Sinatra projects or build new Padrino applications.
11
11
 
12
12
  == Usage
13
13
 
14
- Include padrino-core overview here
14
+ For a comprehensive overview of the whole padrino-framework, check out the
15
+ {Padrino Framework README}[http://github.com/padrino/padrino-framework/blob/master/README.rdoc]
16
+
17
+ Sinatra has support for classes which can be extended to create an application: <tt>Sinatra::Base</tt> and <tt>Sinatra::Application</tt>
18
+ These classes can be extended in order to create a Sinatra web application. These classes provide support for all the basic
19
+ functionality afforded by Sinatra.
20
+
21
+ Padrino has support for an enhanced base application class <tt>Padrino::Application</tt>. <tt>Padrino::Application</tt>
22
+ expands the capabilities of Sinatra::Application and automatically provides the resulting application access to all of
23
+ the padrino framework's functionalities.
24
+
25
+ Similar in spirit to Sinatra itself, Padrino application layout is extremely flexible and can be as small as a single file.
26
+ However, Padrino provides many extensions which improve upon the ability to construct more complex applications.
27
+
28
+ === Simple Application Definition
29
+
30
+ Let us first take a look at the simplest possible Padrino application:
31
+
32
+ # app.rb
33
+ PADRINO_ROOT = File.dirname(__FILE__) unless defined? PADRINO_ROOT
34
+ require 'padrino'
35
+ Padrino.load!
36
+
37
+ class SimpleApp < Padrino::Application
38
+ get '/ do
39
+ 'Hello world'
40
+ end
41
+ end
42
+
43
+ === Gemfile Dependency Resolution
44
+
45
+ While this is a fully operational Padrino application in itself, let us take a look at Padrino's expanded capabilites. First,
46
+ we can create Gemfile within the application root. This will contain a list of all the dependencies for our application.
47
+
48
+ # /Gemfile
49
+ clear_sources
50
+ source 'http://gemcutter.org'
51
+ gem 'sinatra', :require_as => 'sinatra/base'
52
+ gem 'rack-flash'
53
+
54
+ This manifest file uses the standard <tt>bundler</tt> gem syntax of which details can be found in the
55
+ {Bundler README}[http://github.com/wycats/bundler]
56
+ This gem allows us to place all our dependencies into a single file. Padrino will then automatically require
57
+ all necessary files (if they exist on the system).
58
+
59
+ If the dependencies are not on the system, you can automatically vendor all necessary gems
60
+ using the <tt>gem bundle</tt> command within the application root. Note that this is all possible without
61
+ any further effort than adding the Gemfile (or having this generated automatically with generators explained later).
62
+
63
+ === Auto Load Paths
64
+
65
+ Padrino also intelligently supports requiring useful files within your application automatically and provides
66
+ functionality for easily splitting up your application into separate files. Padrino automatically requires <tt>config/database.rb</tt>
67
+ as a convention for establishing database connection. Also, any files within the <tt>lib</tt> folder will be required
68
+ automatically by Padrino.
69
+
70
+ This is powered by the fact that Padrino will automatically load (and reload) any directory patterns within the 'load path'.
71
+ Additional directory patterns can be added to the load path as needed by simply appending to the <tt>load_paths</tt>
72
+ within your application:
73
+
74
+ # app.rb
75
+ class SimpleApp < Padrino::Application
76
+ load_paths << ["app/special/*.rb", "some_file.rb"]
77
+ end
78
+
79
+ This will instruct Padrino to autoload these files (and reload them when changes are detected). By default, the load path
80
+ contains certain paths known to contain important files such as controllers, mailers, models, urls, and helpers.
81
+
82
+ === Initializers
83
+
84
+ Padrino also has support for 'initializers' which are important setup steps or configuration within an application
85
+ that should occur during the bootup process. To construct initializers, simply add a file to the <tt>config/initializers<tt>
86
+ directory following this convention:
87
+
88
+ # config/initializers/example.rb
89
+ module ExampleInitializer
90
+ def self.registered(app)
91
+ # Manipulate 'app' here to register components or adjust configuration
92
+ app.set :environment, :production # just an example configuration change
93
+ app.use Hassle # or even enable middleware
94
+ end
95
+ end
96
+
97
+ Initializers are automatically required and 'registered' during the application startup process. Note that
98
+ the name of the module must be the name of the file appended with 'Initializer' (i.e sample.rb => SampleInitializer)
99
+
100
+ === Controllers
101
+
102
+ Suppose we wanted to add additional routes to our Padrino application, and we want to organize the routes
103
+ within a more structured layout. Simply add a <tt>controllers</tt> or <tt>app/controllers</tt> folder and create a file as such:
104
+
105
+ # controllers/example.rb
106
+ SimpleApp.controllers do
107
+ get "/test" do
108
+ "Text to return"
109
+ end
110
+ end
111
+
112
+ === Application Logging
113
+
114
+ Padrino also supports robust logging capabilities. By default, logging information will
115
+ go to the STDOUT in development (for use in a console) and in an environment-specific log file <tt>log/development.log</tt>
116
+ in test and production environments.
117
+
118
+ You can modify the logging behavior or disable logging altogether:
119
+
120
+ # app.rb
121
+ class SimpleApp < Padrino::Application
122
+ disable :logging # Turns off logging
123
+ enable :log_to_file # Forces logging to be written to a file
124
+ end
125
+
126
+ To use the logger within a Padrino application, simply refer to the <tt>logger</tt> method accessible
127
+ within your app and any controller or views:
128
+
129
+ # controllers/example.rb
130
+ SimpleApp.controllers do
131
+ get("/test") { logger.info "This is a test" }
132
+ end
133
+
134
+ The logger automatically supports severity through the use of <tt>logger.info</tt>, <tt>logger.warn</tt>, <tt>logger.error</tt>, et al.
135
+ For more information about the logger, check out the {Logger RDOC}[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/]
136
+
137
+ === Mounting Applications
138
+
139
+ Padrino applications are all automatically mountable into other Padrino projects. This means that a given Padrino
140
+ project directory can easily mount multiple applications. This allows for better organization of complex applications,
141
+ re-usable applications that can be applied (i.e admin, auth, blog) and even more flexibility.
142
+
143
+ You can think of mountable applications as a 'full-featured' merb slice or rails engine. Instead of a separate construct,
144
+ any application can simply be packaged and mounted into another project.
145
+
146
+ Padrino stores application mounting information by default within <tt>config/apps.rb</tt>. This file is intended
147
+ to keep all information regarding what applications are mounted to which uri's. An <tt>apps.rb</tt> file has
148
+ the following structure:
149
+
150
+ Padrino.mount("blog").to("/blog")
151
+ Padrino.mount("website").to("/website")
152
+
153
+ This would mount two applications onto the Padrino project, one served from the '/blog' uri namespace and the other
154
+ served from the '/website' uri namespace. Often a Padrino project directory requires a single 'core' application
155
+ which is served from the uri root. This can be easily configured using:
156
+
157
+ Padrino.mount_core("app_name") # mounts app with class AppName, in file <tt>app/app.rb</tt>
158
+ Padrino.mount_core("app_name", :app_file => Padrino.root('app.rb')) # now with file in <tt>app.rb</tt>
159
+
160
+ This will mount a 'core' application with class AppName from the file 'app.rb' to the uri root which will
161
+ act as a primary application.
162
+
163
+ === Development Reloader
164
+
165
+ Padrino applications also have the enabled ability to automatically reload all changing application files without
166
+ the need to restart the server. Through the use of a customized Rack middleware, all files on the 'load path'
167
+ are monitored and reloaded whenever changes are applied.
168
+
169
+ This makes rapid development much easier and provides a better alternative to 'shotgun' or 'rerun'
170
+ which require the application server to be restarted which makes requests take much longer to complete.
171
+
172
+ An application can explicitly enable / disable reloading through the use of options:
173
+
174
+ # app.rb
175
+ class SimpleApp < Padrino::Application
176
+ disable :reload # reload is disabled in all environments
177
+ enable :reload # enabled in all environments
178
+ end
179
+
180
+ By default, reloading is enabled in development and disabled in the test and production environments.
181
+
182
+ === Terminal Commands
183
+
184
+ Padrino also comes equipped with multiple useful terminal commands which can be activated to perform
185
+ common tasks such as starting / stopping the application, executing the unit tests or activating an irb session.
186
+
187
+ The following commands are available:
188
+
189
+ # starts the app server (non-daemonized)
190
+ $ padrino start
191
+ # starts the app server (daemonized) with given port, environment and adapter
192
+ $ padrino start -d -p 3000 -e development -a thin
193
+
194
+ # Stops a daemonized app server
195
+ $ padrino stop
196
+
197
+ # Run all the unit tests
198
+ $ padrino test
199
+
200
+ # Bootup the Padrino console (irb)
201
+ $ padrino console
202
+
203
+ Using these commands can simplify common tasks making development that much smoother.
15
204
 
16
205
  == Copyright
17
206
 
data/Rakefile CHANGED
@@ -8,11 +8,13 @@ begin
8
8
  gem.summary = "The required Padrino core gem"
9
9
  gem.description = "The Padrino core gem required for use of this framework"
10
10
  gem.email = "nesquena@gmail.com"
11
- gem.homepage = "http://github.com/padrino/padrino-core"
11
+ gem.homepage = "http://github.com/padrino/padrino-framework/tree/master/padrino-core"
12
12
  gem.authors = ["Padrino Team", "Nathan Esquenazi", "Davide D'Agostino", "Arthur Chiu"]
13
+ gem.executables = ["padrino"]
13
14
  gem.add_runtime_dependency "sinatra", ">= 0.9.2"
14
15
  gem.add_runtime_dependency "thor", ">= 0.11.8"
15
16
  gem.add_development_dependency "haml", ">= 2.2.1"
17
+ gem.add_runtime_dependency "bundler", ">= 0.5.0"
16
18
  gem.add_development_dependency "shoulda", ">= 0"
17
19
  gem.add_development_dependency "mocha", ">= 0.9.7"
18
20
  gem.add_development_dependency "rack-test", ">= 0.5.0"
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.4
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
- %w[rubygems activesupport thor].each { |gem| require gem }
2
+ %w[rubygems thor].each { |gem| require gem }
3
+ require File.dirname(__FILE__) + "/../lib/padrino-core/support_lite"
3
4
  require File.dirname(__FILE__) + "/../lib/padrino-core/tasks"
4
5
 
5
6
  arguments = ARGV.any? ? ARGV : ['-h']
@@ -6,7 +6,6 @@ PADRINO_ENV = ENV["PADRINO_ENV"] ||= ENV["RACK_ENV"] ||= "development" unless de
6
6
 
7
7
  module Padrino
8
8
  class ApplicationLoadError < RuntimeError; end
9
-
10
9
  # Helper method for file references.
11
10
  #
12
11
  # Example:
@@ -16,10 +15,10 @@ module Padrino
16
15
  def self.root(*args)
17
16
  File.join(PADRINO_ROOT, *args)
18
17
  end
19
-
18
+
20
19
  # Helper method that return PADRINO_ENV
21
20
  def self.env
22
- PADRINO_ENV
21
+ PADRINO_ENV.to_s
23
22
  end
24
23
 
25
24
  # Returns the resulting rack builder mapping each 'mounted' application
@@ -11,8 +11,11 @@ module Padrino
11
11
 
12
12
  class << self
13
13
  def inherited(subclass)
14
+ CALLERS_TO_IGNORE.concat(PADRINO_IGNORE_CALLERS)
14
15
  subclass.default_configuration!
15
16
  super # Loading the subclass
17
+ subclass.register Padrino::Routing if defined?(Padrino::Routing)
18
+ subclass.check_single_app
16
19
  end
17
20
 
18
21
  # Hooks into when a new instance of the application is created
@@ -32,39 +35,52 @@ module Padrino
32
35
  include(*extensions) if extensions.any?
33
36
  end
34
37
 
38
+ # Return true if the bootloader => Padrino.load! it's instatiated in the same
39
+ # palace of the app.
40
+ # Notice that <tt>signle_apps</tt> was not reloadable!
41
+ def single_app?
42
+ @_single_app
43
+ end
44
+
35
45
  protected
36
46
 
37
47
  # Setup the application by registering initializers, load paths and logger
38
48
  # Invoked automatically when an application is first instantiated
39
49
  def setup_application!
40
- return if @configured
50
+ return if @_configured
41
51
  self.register_framework_extensions
42
52
  self.calculate_paths
43
53
  self.register_initializers
44
54
  self.require_load_paths
45
55
  self.setup_logger
46
- @configured = true
56
+ @_configured = true
47
57
  end
48
58
 
49
59
  # Defines default settings for Padrino application
50
60
  def default_configuration!
51
61
  # Overwriting Sinatra defaults
62
+ set :app_file, caller_files.first || $0 # Assume app file is first caller
63
+ set :environment, PADRINO_ENV.to_sym
52
64
  set :raise_errors, true if development?
53
- set :logging, true
65
+ set :logging, !test?
54
66
  set :sessions, true
55
67
  set :log_to_file, !development?
56
68
  set :reload, development?
57
69
  # Padrino specific
58
70
  set :app_name, self.to_s.underscore.to_sym
59
- set :environment, PADRINO_ENV.to_sym
60
71
  set :default_builder, 'StandardFormBuilder'
61
72
  enable :flash
62
73
  # Plugin specific
63
- enable :padrino_routing
64
74
  enable :padrino_mailer
65
75
  enable :padrino_helpers
66
76
  end
67
77
 
78
+ def check_single_app
79
+ @_single_app = File.identical?(self.app_file, Padrino.called_from.to_s)
80
+ single_message = "=> Instantiated #{File.basename(self.app_file)} in single app mode, reload is not available"
81
+ puts single_message if @_single_app && logging?
82
+ end
83
+
68
84
  # Calculates any required paths after app_file and root have been properly configured
69
85
  # Executes as part of the setup_application! method
70
86
  def calculate_paths
@@ -76,23 +92,17 @@ module Padrino
76
92
  # Requires the middleware and initializer modules to configure components
77
93
  def register_initializers
78
94
  use Rack::Session::Cookie
79
- use Rack::Flash if flash?
80
- use Padrino::Reloader if reload?
95
+ use Rack::Flash if defined?(Rack::Flash) && flash?
96
+ use Padrino::Reloader unless single_app?
81
97
  register DatabaseSetup if defined?(DatabaseSetup)
82
- Dir[Padrino.root + '/config/initializers/*.rb'].each do |file|
83
- Padrino.load_dependencies(file)
84
- file_class = File.basename(file, '.rb').classify
85
- register "#{file_class}Initializer".constantize
86
- end
98
+ @initializer_path ||= Padrino.root + '/config/initializers/*.rb'
99
+ Dir[@initializer_path].each { |file| register_initializer(file) }
87
100
  end
88
101
 
89
102
  # Registers all desired padrino extension helpers/routing
90
103
  def register_framework_extensions
91
- return if @registered
92
- register Padrino::Routing if padrino_routing?
93
- register Padrino::Mailer if padrino_mailer?
94
- register Padrino::Helpers if padrino_helpers?
95
- @registered = true
104
+ register Padrino::Mailer if padrino_mailer? && defined?(Padrino::Mailer)
105
+ register Padrino::Helpers if padrino_helpers? && defined?(Padrino::Helpers)
96
106
  end
97
107
 
98
108
  # Require all files within the application's load paths
@@ -102,7 +112,7 @@ module Padrino
102
112
 
103
113
  # Creates the log directory and redirects output to file if needed
104
114
  def setup_logger
105
- return unless log_to_file?
115
+ return unless logging? && log_to_file?
106
116
  FileUtils.mkdir_p("#{Padrino.root}/log") unless File.exists?("#{Padrino.root}/log")
107
117
  log = File.new("#{Padrino.root}/log/#{PADRINO_ENV.downcase}.log", "a+")
108
118
  $stdout.reopen(log)
@@ -125,7 +135,20 @@ module Padrino
125
135
  # Resets application routes for use in reloading the application
126
136
  # This performs a basic routes reload (compatible with sinatra edge)
127
137
  def reset_routes!
128
- @routes = Padrino::Application.dupe_routes; load(self.app_file)
138
+ return if single_app? # Don't reset routes for single app
139
+ @routes = Padrino::Application.dupe_routes
140
+ load(self.app_file)
141
+ end
142
+
143
+ # Registers an initializer with the application
144
+ # register_initializer('/path/to/initializer')
145
+ def register_initializer(file_path)
146
+ Padrino.load_dependencies(file_path)
147
+ file_class = File.basename(file_path, '.rb').camelize
148
+ register "#{file_class}Initializer".constantize
149
+ rescue NameError => e
150
+ puts "The module '#{file_class}Initializer' (#{file_path}) didn't loaded properly!" if logging?
151
+ puts " Initializer error was '#{e.message}'" if logging?
129
152
  end
130
153
  end
131
154
  end
@@ -0,0 +1,35 @@
1
+ module Padrino
2
+ PADRINO_IGNORE_CALLERS = [
3
+ %r{/padrino-.*$}, # all padrino code
4
+ %r{/sinatra}, # all sinatra code
5
+ %r{lib/tilt.*\.rb$}, # all tilt code
6
+ %r{\(.*\)}, # generated code
7
+ %r{shoulda/context\.rb$}, # shoulda hacks
8
+ %r{mocha/integration}, # mocha hacks
9
+ %r{test/unit}, # test unit hacks
10
+ %r{rake_test_loader\.rb}, # rake hacks
11
+ %r{custom_require\.rb$}, # rubygems require hacks
12
+ %r{active_support}, # active_support require hacks
13
+ %r{/thor}, # thor require hacks
14
+ ]
15
+
16
+ # add rubinius (and hopefully other VM impls) ignore patterns ...
17
+ PADRINO_IGNORE_CALLERS.concat(RUBY_IGNORE_CALLERS) if defined?(RUBY_IGNORE_CALLERS)
18
+
19
+ # Returns the filename for the file that is the direct caller (first caller)
20
+ def self.first_caller
21
+ caller_files.first
22
+ end
23
+
24
+ # Like Kernel#caller but excluding certain magic entries and without
25
+ # line / method information; the resulting array contains filenames only.
26
+ def self.caller_files
27
+ caller_locations.map { |file,line| file }
28
+ end
29
+
30
+ def self.caller_locations
31
+ caller(1).
32
+ map { |line| line.split(/:(?=\d|in )/)[0,2] }.
33
+ reject { |file,line| PADRINO_IGNORE_CALLERS.any? { |pattern| file =~ pattern } }
34
+ end
35
+ end
@@ -2,15 +2,29 @@ module Padrino
2
2
  class << self
3
3
  # Requires necessary dependencies as well as application files from root lib and models
4
4
  def load!
5
+ return if loaded?
6
+ @_called_from = first_caller
5
7
  load_required_gems # load bundler gems
6
8
  load_dependencies("#{root}/config/apps.rb", "#{root}/config/database.rb") # load configuration
7
9
  load_dependencies("#{root}/lib/**/*.rb", "#{root}/models/*.rb") # load root app dependencies
8
10
  reload! # We need to fill our Stat::CACHE but we do that only for development
11
+ @_loaded = true
9
12
  end
10
13
 
11
- # Method for reload required classes
12
- def reload!
13
- Stat::reload!
14
+ # This adds the ablity to instantiate Padrino.load! after Padrino::Application definition.
15
+ def called_from
16
+ @_called_from || first_caller
17
+ end
18
+
19
+ # Return true if Padrino was loaded with Padrino.load!
20
+ def loaded?
21
+ @_loaded
22
+ end
23
+
24
+ # Attempts to require all dependencies with bundler; if this fails, uses system wide gems
25
+ def load_required_gems
26
+ load_bundler_manifest
27
+ require_vendored_gems
14
28
  end
15
29
 
16
30
  # Attempts to load/require all dependency libs that we need.
@@ -26,24 +40,34 @@ module Padrino
26
40
  end
27
41
  alias_method :load_dependency, :load_dependencies
28
42
 
29
- # Attempts to require all dependencies with bundler; if fails, we try to use system wide gems
30
- def load_required_gems
31
- begin
32
- require 'bundler'
33
- gemfile_path = root("Gemfile")
34
- puts "=> Loading GemFile #{gemfile_path} for #{PADRINO_ENV}"
35
- # TODO possibly support padrino apps where no Gemfile is specified (skip requires, assume explicit dependencies)
36
- Bundler::Environment.load(gemfile_path).require_env(PADRINO_ENV)
37
- rescue Bundler::DefaultManifestNotFound => e
38
- puts "=> You didn't create Bundler Gemfile manifest or you are not in a Sinatra application."
39
- end
43
+ # Method for reload required classes
44
+ def reload!
45
+ Stat::reload!
46
+ end
40
47
 
41
- begin
42
- load_dependencies(root('/../vendor', 'gems', PADRINO_ENV))
43
- puts "=> Using bundled gems"
44
- rescue LoadError => e
45
- puts "=> Using system wide gems (No bundled gems)"
46
- end
48
+ protected
49
+
50
+ # Loads the bundler manifest Gemfile if it exists
51
+ def load_bundler_manifest
52
+ require 'bundler'
53
+ say "=> Locating Gemfile for #{PADRINO_ENV}"
54
+ Bundler::Environment.load(root("Gemfile")).require_env(PADRINO_ENV)
55
+ say " ... Loaded!"
56
+ rescue Bundler::ManifestFileNotFound, Bundler::DefaultManifestNotFound => e
57
+ say " ... Not Found"
58
+ end
59
+
60
+ # Loads bundled gems if they exist
61
+ def require_vendored_gems
62
+ load_dependencies(root('/../vendor', 'gems', PADRINO_ENV))
63
+ say " (Loading bundled gems)\n"
64
+ rescue LoadError => e
65
+ say " (Loading system gems)\n"
66
+ end
67
+
68
+ # Prints out a message to the stdout if not in test environment
69
+ def say(text)
70
+ print text if Padrino.env != 'test'
47
71
  end
48
72
  end
49
73
  end