halcyon 0.4.0 → 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.
- data/AUTHORS +1 -0
- data/LICENSE +20 -0
- data/README +107 -0
- data/Rakefile +8 -6
- data/bin/halcyon +3 -204
- data/lib/halcyon.rb +55 -42
- data/lib/halcyon/application.rb +247 -0
- data/lib/halcyon/application/router.rb +86 -0
- data/lib/halcyon/client.rb +187 -35
- data/lib/halcyon/client/ssl.rb +38 -0
- data/lib/halcyon/controller.rb +154 -0
- data/lib/halcyon/exceptions.rb +67 -59
- data/lib/halcyon/logging.rb +31 -0
- data/lib/halcyon/logging/analogger.rb +31 -0
- data/lib/halcyon/logging/helpers.rb +37 -0
- data/lib/halcyon/logging/log4r.rb +25 -0
- data/lib/halcyon/logging/logger.rb +20 -0
- data/lib/halcyon/logging/logging.rb +19 -0
- data/lib/halcyon/runner.rb +141 -0
- data/lib/halcyon/runner/commands.rb +141 -0
- data/lib/halcyon/runner/helpers.rb +9 -0
- data/lib/halcyon/runner/helpers/command_helper.rb +71 -0
- data/spec/halcyon/application_spec.rb +70 -0
- data/spec/halcyon/client_spec.rb +63 -0
- data/spec/halcyon/controller_spec.rb +68 -0
- data/spec/halcyon/halcyon_spec.rb +63 -0
- data/spec/halcyon/logging_spec.rb +31 -0
- data/spec/halcyon/router_spec.rb +37 -12
- data/spec/halcyon/runner_spec.rb +54 -0
- data/spec/spec_helper.rb +75 -9
- data/support/generators/halcyon/USAGE +0 -0
- data/support/generators/halcyon/halcyon_generator.rb +52 -0
- data/support/generators/halcyon/templates/README +26 -0
- data/support/generators/halcyon/templates/Rakefile +32 -0
- data/support/generators/halcyon/templates/app/application.rb +43 -0
- data/support/generators/halcyon/templates/config/config.yml +36 -0
- data/support/generators/halcyon/templates/config/init/environment.rb +11 -0
- data/support/generators/halcyon/templates/config/init/hooks.rb +39 -0
- data/support/generators/halcyon/templates/config/init/requires.rb +10 -0
- data/support/generators/halcyon/templates/config/init/routes.rb +50 -0
- data/support/generators/halcyon/templates/lib/client.rb +77 -0
- data/support/generators/halcyon/templates/runner.ru +8 -0
- data/support/generators/halcyon_flat/USAGE +0 -0
- data/support/generators/halcyon_flat/halcyon_flat_generator.rb +52 -0
- data/support/generators/halcyon_flat/templates/README +26 -0
- data/support/generators/halcyon_flat/templates/Rakefile +32 -0
- data/support/generators/halcyon_flat/templates/app.rb +49 -0
- data/support/generators/halcyon_flat/templates/lib/client.rb +17 -0
- data/support/generators/halcyon_flat/templates/runner.ru +8 -0
- metadata +73 -20
- data/lib/halcyon/client/base.rb +0 -261
- data/lib/halcyon/client/exceptions.rb +0 -41
- data/lib/halcyon/client/router.rb +0 -106
- data/lib/halcyon/server.rb +0 -62
- data/lib/halcyon/server/auth/basic.rb +0 -107
- data/lib/halcyon/server/base.rb +0 -774
- data/lib/halcyon/server/exceptions.rb +0 -41
- data/lib/halcyon/server/router.rb +0 -103
- data/spec/halcyon/error_spec.rb +0 -55
- data/spec/halcyon/server_spec.rb +0 -105
File without changes
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
class HalcyonGenerator < RubiGen::Base
|
4
|
+
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
5
|
+
Config::CONFIG['ruby_install_name'])
|
6
|
+
|
7
|
+
default_options :shebang => DEFAULT_SHEBANG
|
8
|
+
|
9
|
+
attr_reader :app_name, :module_name
|
10
|
+
|
11
|
+
def initialize(runtime_args, runtime_options = {})
|
12
|
+
super
|
13
|
+
usage if args.empty?
|
14
|
+
@destination_root = args.shift
|
15
|
+
@app_name = File.basename(File.expand_path(@destination_root))
|
16
|
+
@module_name = app_name.camelize
|
17
|
+
# extract_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def manifest
|
21
|
+
record do |m|
|
22
|
+
source = File.expand_path(File.join(File.dirname(__FILE__), 'templates')) << File::Separator
|
23
|
+
|
24
|
+
m.directory ''
|
25
|
+
Dir[source + '**/*'].each do |path|
|
26
|
+
path = path.sub(source, '')
|
27
|
+
if File.directory?(source+path)
|
28
|
+
m.directory path
|
29
|
+
else
|
30
|
+
m.template path, path, :assigns => {:app => @module_name, :unix => @app_name}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
m.directory 'log'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
def banner
|
39
|
+
<<-"end;"
|
40
|
+
Create a stub for #{File.basename $0} to get started.
|
41
|
+
|
42
|
+
Usage: #{File.basename $0} [options] /path/to/your/app"
|
43
|
+
end;
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_options!(opts)
|
47
|
+
opts.separator ''
|
48
|
+
opts.separator "#{File.basename $0} options:"
|
49
|
+
opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
%w(rubygems rake rake/clean rake/rdoctask fileutils pp halcyon).each{|dep|require dep}
|
2
|
+
|
3
|
+
include FileUtils
|
4
|
+
|
5
|
+
# Halcyon.root => the root application directory
|
6
|
+
# Halcyon.app => the application name
|
7
|
+
|
8
|
+
desc "Start the application on port 4647"
|
9
|
+
task :start do
|
10
|
+
sh "halcyon start -p 4647"
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Generate RDoc documentation"
|
14
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
15
|
+
rdoc.options << '--line-numbers' << '--inline-source' <<
|
16
|
+
'--main' << 'README' <<
|
17
|
+
'--title' << "#{Halcyon.app} Documentation" <<
|
18
|
+
'--charset' << 'utf-8'
|
19
|
+
rdoc.rdoc_dir = "doc"
|
20
|
+
rdoc.rdoc_files.include('README')
|
21
|
+
rdoc.rdoc_files.include('app/**/*.rb')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
24
|
+
|
25
|
+
# = Custom Rake Tasks
|
26
|
+
#
|
27
|
+
# Add your custom rake tasks here.
|
28
|
+
|
29
|
+
# ...
|
30
|
+
|
31
|
+
# = Default Task
|
32
|
+
task :default => Rake::Task['start']
|
@@ -0,0 +1,43 @@
|
|
1
|
+
class Application < Halcyon::Controller
|
2
|
+
|
3
|
+
# Summary of available services
|
4
|
+
#
|
5
|
+
# This method is just a sample and can be removed altogether. It may be
|
6
|
+
# advised to advertise available functionality for public-facing applications
|
7
|
+
# to clarify usage.
|
8
|
+
#
|
9
|
+
# Returns [{:path=>String:path,Symbol:method=>[Hash:params, *:sample],...},...]
|
10
|
+
def index
|
11
|
+
ok([
|
12
|
+
{
|
13
|
+
:path => "/time",
|
14
|
+
:GET => [{}, Time.now.to_s],
|
15
|
+
:POST => [{:format => "strftime compatible"}, Time.now.strftime("%Y-%m-%dT%H:%M%:%S%Z")]
|
16
|
+
},
|
17
|
+
{
|
18
|
+
:path => "/",
|
19
|
+
:GET => [{}, "[{:path=>String:path,Symbol:method=>[Hash:params, *:sample],...},...]"]
|
20
|
+
}
|
21
|
+
])
|
22
|
+
end
|
23
|
+
|
24
|
+
# Responds with the current time in either generic or specific formats
|
25
|
+
#
|
26
|
+
# GET
|
27
|
+
# returns the current time
|
28
|
+
# POST
|
29
|
+
# returns the current time formatted acccording to +format+
|
30
|
+
#
|
31
|
+
# Returns String:time
|
32
|
+
def time
|
33
|
+
case method
|
34
|
+
when :get
|
35
|
+
ok(Time.now.to_s)
|
36
|
+
when :post
|
37
|
+
ok(Time.now.strftime(post[:format] || "%Y-%m-%dT%H:%M%:%S%Z"))
|
38
|
+
else
|
39
|
+
raise NotImplemented.new
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# = Framework
|
2
|
+
#
|
3
|
+
# <tt>allow_from</tt>: specifies what connections to accept;
|
4
|
+
# * <tt>all</tt>: allow connections from all clients
|
5
|
+
# * <tt>local</tt>: only allow connections from the same host (localhost et al)
|
6
|
+
# * <tt>halcyon_clients</tt>: only Halcyon clients (tests the User-Agent only)
|
7
|
+
allow_from: all
|
8
|
+
|
9
|
+
# = Environment
|
10
|
+
#
|
11
|
+
# Uncomment to manually specify the environment to run the application in.
|
12
|
+
# Defaults to <tt>:development</tt>.
|
13
|
+
#
|
14
|
+
# environment: production
|
15
|
+
|
16
|
+
# = Logging
|
17
|
+
#
|
18
|
+
# Configures the logging client in the framework, including destination,
|
19
|
+
# level filter, and what logger to use.
|
20
|
+
#
|
21
|
+
# <tt>type</tt>: the logger to use (defaults to Ruby's <tt>Logger</tt>)
|
22
|
+
# * <tt>Logger</tt>
|
23
|
+
# * <tt>Analogger</tt>
|
24
|
+
# * <tt>Logging</tt>
|
25
|
+
# * <tt>Log4r</tt>
|
26
|
+
# <tt>file</tt>: the log file; leave unset for STDOUT
|
27
|
+
# <tt>level</tt>: the message filter level (default to <tt>debug</tt>)
|
28
|
+
# * specific to the client used, often is: debug, info, warn, error, fatal
|
29
|
+
logging:
|
30
|
+
type: Logger
|
31
|
+
# file: # STDOUT
|
32
|
+
level: debug
|
33
|
+
|
34
|
+
# = Application
|
35
|
+
#
|
36
|
+
# Your application-specific configuration options here.
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# = Environment
|
2
|
+
#
|
3
|
+
# Sets the environment unless already set.
|
4
|
+
#
|
5
|
+
# Creates the <tt>Halcyon.environment</tt> configurable attribute. Since this
|
6
|
+
# is mapped to <tt>Halcyon.config[:environment]</tt>, environment can be set
|
7
|
+
# by setting the <tt>environment:</tt> configuration value in the
|
8
|
+
# <tt>config/config.yml</tt> file.
|
9
|
+
|
10
|
+
Halcyon.configurable_attr(:environment)
|
11
|
+
Halcyon.environment = :development unless Halcyon.environment
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# = Hooks
|
2
|
+
#
|
3
|
+
# Specify actions to run at specific times during the application's execution,
|
4
|
+
# such as the startup or shutdown events.
|
5
|
+
#
|
6
|
+
# Available Hooks
|
7
|
+
# +startup+
|
8
|
+
# +shutdown+
|
9
|
+
#
|
10
|
+
# All hooks take the current application configuration as its sole block param.
|
11
|
+
#
|
12
|
+
# Examples
|
13
|
+
# Halcyon::Application.startup do |config|
|
14
|
+
# # Halcyon.db set in config/initialize/database.rb
|
15
|
+
# ::DB = Sequel(Halcyon.db)
|
16
|
+
# logger.info "Connected to database"
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# The +logger+ object is available to log messages on status or otherwise.
|
20
|
+
|
21
|
+
# = Startup
|
22
|
+
#
|
23
|
+
# Run when the Halcyon::Application object is instanciated, after all
|
24
|
+
# initializers are loaded.
|
25
|
+
#
|
26
|
+
# Ideal for establishing connections to resources like databases.
|
27
|
+
# Establish configuration options in initializer files, though.
|
28
|
+
Halcyon::Application.startup do |config|
|
29
|
+
logger.info 'Define startup tasks in config/init/hooks.rb'
|
30
|
+
end
|
31
|
+
|
32
|
+
# = Shutdown
|
33
|
+
#
|
34
|
+
# Run <tt>at_exit</tt>. Should run in most cases of termination.
|
35
|
+
#
|
36
|
+
# Ideal for closing connections to resources.
|
37
|
+
Halcyon::Application.shutdown do |config|
|
38
|
+
logger.info 'Define shutdown tasks in config/init/hooks.rb'
|
39
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# = Required Libraries
|
2
|
+
#
|
3
|
+
# Specify required libraries specific to the operation of your application.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
# %(digest/md5 tempfile date).each{|dep|require dep}
|
7
|
+
#
|
8
|
+
# RubyGems should already be required by Halcyon, so don't include it.
|
9
|
+
|
10
|
+
%w().each{|dep|require dep}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# = Routes
|
2
|
+
#
|
3
|
+
# Halcyon::Application::Router is the request routing mapper for the merb
|
4
|
+
# framework.
|
5
|
+
#
|
6
|
+
# You can route a specific URL to a controller / action pair:
|
7
|
+
#
|
8
|
+
# r.match("/contact").
|
9
|
+
# to(:controller => "info", :action => "contact")
|
10
|
+
#
|
11
|
+
# You can define placeholder parts of the url with the :symbol notation. These
|
12
|
+
# placeholders will be available in the params hash of your controllers. For example:
|
13
|
+
#
|
14
|
+
# r.match("/books/:book_id/:action").
|
15
|
+
# to(:controller => "books")
|
16
|
+
#
|
17
|
+
# Or, use placeholders in the "to" results for more complicated routing, e.g.:
|
18
|
+
#
|
19
|
+
# r.match("/admin/:module/:controller/:action/:id").
|
20
|
+
# to(:controller => ":module/:controller")
|
21
|
+
#
|
22
|
+
# You can also use regular expressions, deferred routes, and many other options.
|
23
|
+
# See merb/specs/merb/router.rb for a fairly complete usage sample.
|
24
|
+
#
|
25
|
+
# Stolen directly from generated Merb app. All documentation applies.
|
26
|
+
# Read more about the Merb router at http://merbivore.com/.
|
27
|
+
Halcyon::Application.route do |r|
|
28
|
+
|
29
|
+
# Sample route for the sample functionality in Application.
|
30
|
+
# Safe to remove!
|
31
|
+
r.match('/time').to(:controller => 'application', :action => 'time')
|
32
|
+
|
33
|
+
# RESTful routes
|
34
|
+
# r.resources :posts
|
35
|
+
|
36
|
+
# This is the default route for /:controller/:action/:id
|
37
|
+
# This is fine for most cases. If you're heavily using resource-based
|
38
|
+
# routes, you may want to comment/remove this line to prevent
|
39
|
+
# clients from calling your create or destroy actions with a GET
|
40
|
+
r.default_routes
|
41
|
+
|
42
|
+
# Change this for the default route to be available at /
|
43
|
+
r.match('/').to(:controller => 'application', :action => 'index')
|
44
|
+
# It can often be useful to respond with available functionality if the
|
45
|
+
# application is a public-facing service.
|
46
|
+
|
47
|
+
# Default not-found route
|
48
|
+
{:action => 'not_found'}
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
%w(rubygems halcyon).each{|dep|require dep}
|
2
|
+
|
3
|
+
module <%= app %>
|
4
|
+
|
5
|
+
# = Client
|
6
|
+
#
|
7
|
+
# The client interface for accessing services provided by the Halcyon
|
8
|
+
# application as defined in the controllers in <tt>app/</tt>.
|
9
|
+
#
|
10
|
+
# == Usage
|
11
|
+
#
|
12
|
+
# To use the Client in your application, create an instance and call methods
|
13
|
+
# defined here. For example:
|
14
|
+
#
|
15
|
+
# client = <%= app %>::Client.new('http://localhost:4647/')
|
16
|
+
# client.time #=> "Tue Apr 15 21:04:15 -0400 2008"
|
17
|
+
#
|
18
|
+
# You can just as easily call the primary <tt>get</tt>, <tt>post</tt>,
|
19
|
+
# <tt>put</tt>, and <tt>delete</tt> methods as well, passing in the +path+
|
20
|
+
# and any params. For example:
|
21
|
+
#
|
22
|
+
# client.get('/time') #=> "Tue Apr 15 21:04:15 -0400 2008"
|
23
|
+
#
|
24
|
+
# By default, if you enter a bad (non-existent) path or the application
|
25
|
+
# raises an exception and cannot complete successfully, the standard response
|
26
|
+
# format will be returned but with more appropriate +status+ and +body+
|
27
|
+
# values. For instance:
|
28
|
+
#
|
29
|
+
# client.get('/nonexistent/path') #=> {:status=>404,:body=>"Not Found"}
|
30
|
+
#
|
31
|
+
# Exceptions can be raised on any +status+ returned other than +200+ if you
|
32
|
+
# set <tt>Halcyon::Client#raise_exceptions!</tt> to +true+ (which is the
|
33
|
+
# default param).
|
34
|
+
#
|
35
|
+
# client.raise_exceptions! #=> true
|
36
|
+
# client.get('/nonexistent/path') #=> NotFound exception is raised
|
37
|
+
#
|
38
|
+
# These exceptions all inherit from <tt>Halcyon::Exceptions::Base</tt> so
|
39
|
+
# <tt>rescue</tt>ing just normal Halcyon errors is trivial.
|
40
|
+
#
|
41
|
+
# However, setting this value can cause the meaning and the appropriate
|
42
|
+
# error-handling measures put in place in actions. Although each method
|
43
|
+
# could just as easily set the +raise_exceptions+ configuration option
|
44
|
+
# itself, it is not advised to do so due to the possibility of non-
|
45
|
+
# consistent and confusing behavior it can cause.
|
46
|
+
#
|
47
|
+
# If raising exceptions is preferred, it should be set as soon as the
|
48
|
+
# client is created and the client methods should be designed accordingly.
|
49
|
+
class Client < Halcyon::Client
|
50
|
+
|
51
|
+
def self.version
|
52
|
+
VERSION.join('.')
|
53
|
+
end
|
54
|
+
|
55
|
+
# Sample of a client method to wrap an API call
|
56
|
+
def time
|
57
|
+
get('/time')[:body]
|
58
|
+
end
|
59
|
+
|
60
|
+
# More comprehensive sample client method
|
61
|
+
def strftime(format = nil)
|
62
|
+
if (res = post('/time', :format => format))[:status] == 200
|
63
|
+
# success
|
64
|
+
res[:body]
|
65
|
+
else
|
66
|
+
# failure
|
67
|
+
# returns the whole response to indicate an error happened, but could
|
68
|
+
# just as easily raise an exception.
|
69
|
+
# but if an exception is prefererd, read the documentation for
|
70
|
+
# <tt>Halcyon::Client#raise_exceptions!</tt> instead.
|
71
|
+
res
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
File without changes
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
class HalcyonFlatGenerator < RubiGen::Base
|
4
|
+
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
5
|
+
Config::CONFIG['ruby_install_name'])
|
6
|
+
|
7
|
+
default_options :shebang => DEFAULT_SHEBANG
|
8
|
+
|
9
|
+
attr_reader :app_name, :module_name
|
10
|
+
|
11
|
+
def initialize(runtime_args, runtime_options = {})
|
12
|
+
super
|
13
|
+
usage if args.empty?
|
14
|
+
@destination_root = args.shift
|
15
|
+
@app_name = File.basename(File.expand_path(@destination_root))
|
16
|
+
@module_name = app_name.camelize
|
17
|
+
# extract_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def manifest
|
21
|
+
record do |m|
|
22
|
+
source = File.expand_path(File.join(File.dirname(__FILE__), 'templates')) << File::Separator
|
23
|
+
|
24
|
+
m.directory ''
|
25
|
+
Dir[source + '**/*'].each do |path|
|
26
|
+
path = path.sub(source, '')
|
27
|
+
if File.directory?(source+path)
|
28
|
+
m.directory path
|
29
|
+
else
|
30
|
+
m.template path, path, :assigns => {:app => @module_name, :unix => @app_name}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
m.directory 'log'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
def banner
|
39
|
+
<<-"end;"
|
40
|
+
Create a stub for #{File.basename $0} to get started.
|
41
|
+
|
42
|
+
Usage: #{File.basename $0} [options] /path/to/your/app"
|
43
|
+
end;
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_options!(opts)
|
47
|
+
opts.separator ''
|
48
|
+
opts.separator "#{File.basename $0} options:"
|
49
|
+
opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|