halcyon 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/AUTHORS +1 -0
  2. data/LICENSE +20 -0
  3. data/README +107 -0
  4. data/Rakefile +8 -6
  5. data/bin/halcyon +3 -204
  6. data/lib/halcyon.rb +55 -42
  7. data/lib/halcyon/application.rb +247 -0
  8. data/lib/halcyon/application/router.rb +86 -0
  9. data/lib/halcyon/client.rb +187 -35
  10. data/lib/halcyon/client/ssl.rb +38 -0
  11. data/lib/halcyon/controller.rb +154 -0
  12. data/lib/halcyon/exceptions.rb +67 -59
  13. data/lib/halcyon/logging.rb +31 -0
  14. data/lib/halcyon/logging/analogger.rb +31 -0
  15. data/lib/halcyon/logging/helpers.rb +37 -0
  16. data/lib/halcyon/logging/log4r.rb +25 -0
  17. data/lib/halcyon/logging/logger.rb +20 -0
  18. data/lib/halcyon/logging/logging.rb +19 -0
  19. data/lib/halcyon/runner.rb +141 -0
  20. data/lib/halcyon/runner/commands.rb +141 -0
  21. data/lib/halcyon/runner/helpers.rb +9 -0
  22. data/lib/halcyon/runner/helpers/command_helper.rb +71 -0
  23. data/spec/halcyon/application_spec.rb +70 -0
  24. data/spec/halcyon/client_spec.rb +63 -0
  25. data/spec/halcyon/controller_spec.rb +68 -0
  26. data/spec/halcyon/halcyon_spec.rb +63 -0
  27. data/spec/halcyon/logging_spec.rb +31 -0
  28. data/spec/halcyon/router_spec.rb +37 -12
  29. data/spec/halcyon/runner_spec.rb +54 -0
  30. data/spec/spec_helper.rb +75 -9
  31. data/support/generators/halcyon/USAGE +0 -0
  32. data/support/generators/halcyon/halcyon_generator.rb +52 -0
  33. data/support/generators/halcyon/templates/README +26 -0
  34. data/support/generators/halcyon/templates/Rakefile +32 -0
  35. data/support/generators/halcyon/templates/app/application.rb +43 -0
  36. data/support/generators/halcyon/templates/config/config.yml +36 -0
  37. data/support/generators/halcyon/templates/config/init/environment.rb +11 -0
  38. data/support/generators/halcyon/templates/config/init/hooks.rb +39 -0
  39. data/support/generators/halcyon/templates/config/init/requires.rb +10 -0
  40. data/support/generators/halcyon/templates/config/init/routes.rb +50 -0
  41. data/support/generators/halcyon/templates/lib/client.rb +77 -0
  42. data/support/generators/halcyon/templates/runner.ru +8 -0
  43. data/support/generators/halcyon_flat/USAGE +0 -0
  44. data/support/generators/halcyon_flat/halcyon_flat_generator.rb +52 -0
  45. data/support/generators/halcyon_flat/templates/README +26 -0
  46. data/support/generators/halcyon_flat/templates/Rakefile +32 -0
  47. data/support/generators/halcyon_flat/templates/app.rb +49 -0
  48. data/support/generators/halcyon_flat/templates/lib/client.rb +17 -0
  49. data/support/generators/halcyon_flat/templates/runner.ru +8 -0
  50. metadata +73 -20
  51. data/lib/halcyon/client/base.rb +0 -261
  52. data/lib/halcyon/client/exceptions.rb +0 -41
  53. data/lib/halcyon/client/router.rb +0 -106
  54. data/lib/halcyon/server.rb +0 -62
  55. data/lib/halcyon/server/auth/basic.rb +0 -107
  56. data/lib/halcyon/server/base.rb +0 -774
  57. data/lib/halcyon/server/exceptions.rb +0 -41
  58. data/lib/halcyon/server/router.rb +0 -103
  59. data/spec/halcyon/error_spec.rb +0 -55
  60. 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,26 @@
1
+ = Application
2
+
3
+
4
+ == Introduction
5
+
6
+ ...
7
+
8
+
9
+ == Installation
10
+
11
+ ...
12
+
13
+
14
+ === Dependencies
15
+
16
+ * Halcyon (halcyon >= 0.5.0)
17
+ * ...
18
+
19
+ == License
20
+
21
+ ...
22
+
23
+
24
+ == Contact
25
+
26
+ ...
@@ -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
@@ -0,0 +1,8 @@
1
+ require 'halcyon'
2
+
3
+ $:.unshift(Halcyon.root/'lib')
4
+
5
+ puts "(Starting in #{Halcyon.root})"
6
+
7
+ Thin::Logging.silent = true if defined? Thin
8
+ run Halcyon::Runner.new
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