padrino-core 0.1.3 → 0.1.4

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