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