rubyrest 0.0.5 → 0.1.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.
@@ -1,49 +1,45 @@
1
- # RubyRest: $Id:$
2
- #
3
- #
4
- #
5
-
6
1
  module RubyRest
7
2
 
8
- # Objects of this class take a configuration as argument
9
- # then launch a new server instance.
3
+ # The Ruby-on-Rest Engine is the glue between
4
+ # the custom application and the webserver implementation
10
5
  class Engine
11
- include Tools
12
6
 
13
- # Enables external objects to read the
14
- # engine configuration
15
- attr_reader :config
7
+ # The application
8
+ attr_reader :app
16
9
 
17
- # Creates a new RubyRest engine, for the specified
18
- # hash of configuration data. The specified hash of params
19
- # will be 'interned' so that config keys are accessible
20
- # as symbols instead of strings.
21
- def initialize( original )
22
- params = {}
23
- original.each{ |k,v| params[ k.intern ] = v }
24
- @service = params[ :service ]
25
- @prefix = params[ :prefix ]
26
- service_module = to_module_name( @prefix, @service )
27
- require @service
28
- @config = to_class( service_module, "config" ).new( params )
29
- @config[ :servicemodule ] = service_module
10
+ # Initializes the Ruby-on-Rest Engine, Application and Webserver.
11
+ # The Application must be installed as a rubygem so that
12
+ # the statement +require @service+ works.
13
+ def initialize( config )
14
+ params = intern_config( config )
15
+ require params[:service]
16
+ @app = Class.by_name( params[:module].capitalize + "::" + params[:service].capitalize + "::Application" ).new( params )
17
+ if params[:daemon ] != nil
18
+ @daemon = params[:daemon ]
19
+ else @daemon=true end
20
+ @server = Class.by_name( "RubyRest::" + params[:webserver].to_s.capitalize + "::Server" ).new( @app )
30
21
  end
31
22
 
32
- # Starts the engine. The following operations are accomplished:
33
- #
34
- # 1. configure the database
35
- # 2. launch the webserver, in daemon mode unless false is
36
- # specified in the configuration
23
+
24
+ # Returns a new hash, with all the keys as symbols
25
+ def intern_config( hash )
26
+ interned = Hash.new
27
+ hash.each{ |k,v| interned[ k.intern ] = v }
28
+ return interned
29
+ end
30
+
31
+ # Starts the server, embedded or as a detached
32
+ # daemon
37
33
  def start
38
- configure_database if @config.has( :adapter )
39
- @server = RubyRest::Server.new( @config )
40
- @server.mount "/", CRUDServlet
41
- if @config.has( :daemon ) and @config[ :daemon ] == false
42
- start_server
43
- else start_daemon end
34
+ if @daemon
35
+ @pid = fork do
36
+ @server.up
37
+ end
38
+ puts "#{self.to_s}: started - pid=#{@pid}, port=#{@app.config[:http_port]}"
39
+ else @server.up end
44
40
  end
45
41
 
46
- # Shutdowns the current server, if existing.
42
+ # Shutdowns the current server.
47
43
  # This is only useful when working in daemon mode.
48
44
  def stop
49
45
  return if @pid == nil
@@ -51,56 +47,11 @@ module RubyRest
51
47
  puts "#{self.to_s}: killed process with pid=#{@pid}"
52
48
  end
53
49
 
54
- # Configures the database connectivity
55
- def configure_database
56
- @config.connect_to_database
57
- @config.setup_persistence
58
- if @config[ :destroy ] == true
59
- @config.init_schema
60
- @config.load_initial_data
61
- end
62
- end
63
-
64
- # Starts the server in another process
65
- def start_daemon
66
- @pid = fork do
67
- start_server
68
- end
69
- puts "#{self.to_s}: started process with pid=#{@pid}"
70
- end
71
-
72
- # Starts the server
73
- def start_server
74
- [ "INT", "TERM" ].each { |signal|
75
- trap( signal ) { @server.shutdown }
76
- }
77
- @server.start
78
- end
79
-
80
- # Returns the service name
50
+ # Returns the deployed application name
81
51
  def to_s
82
- "rubyrest: #{@service}"
52
+ "rubyrest: #{@app}"
83
53
  end
84
54
 
85
55
  end
86
56
 
87
-
88
- # Adds some extra functionnality to the actual server
89
- # implementation.
90
- #
91
- class Server < WEBrick::HTTPServer
92
-
93
- # the configuration options
94
- attr_accessor :rubyrest
95
-
96
- # Creates a new WEBrick instance with the specified
97
- # configuration
98
- def initialize( config )
99
- super( :Port => config[ :serviceport ] )
100
- @rubyrest = config
101
- end
102
-
103
- end
104
-
105
-
106
57
  end
@@ -0,0 +1,87 @@
1
+ module RubyRest
2
+
3
+ # Base REST Resource class that acts as a wrapper for the actual
4
+ # business logic, data formatting (response time) and validations (request time)
5
+ class Resource
6
+
7
+ # Creates a new resource, under the given application
8
+ def initialize( app )
9
+ @app = app
10
+ end
11
+
12
+ # Convenience method
13
+ def service
14
+ self.class.service
15
+ end
16
+
17
+ # Convenience method
18
+ def model
19
+ self.class.model
20
+ end
21
+
22
+ # Defines the url type the resource is going to
23
+ # handle
24
+ def self.with_mount_point path
25
+ @mount_point = path
26
+ end
27
+
28
+ def self.mount_point
29
+ @mount_point
30
+ end
31
+
32
+ def self.for_model model_klass
33
+ @model = model_klass
34
+ end
35
+
36
+ def self.model
37
+ @model || Class.by_name( self.name + "Model" )
38
+ end
39
+
40
+ def self.for_service service_klass
41
+ @service = service_klass
42
+ end
43
+
44
+ def self.service
45
+ @service || Class.by_name( self.name + "Service" )
46
+ end
47
+
48
+ def self.atom modifiers
49
+ self.props << modifiers
50
+ end
51
+
52
+ # Returns the list of formatters
53
+ def self.props
54
+ @props = [] if !@props
55
+ return @props
56
+ end
57
+
58
+ # Declares a new link
59
+ def self.link modifiers
60
+ self.links << modifiers
61
+ end
62
+
63
+ # Returns the array of links declared
64
+ # for the resource
65
+ def self.links
66
+ @links = [] if !@links
67
+ return @links
68
+ end
69
+
70
+ # Updates the specified object with the data found
71
+ # in the specified xml object, and the rules defined in
72
+ # the resource parsers
73
+ def bind( object, xml )
74
+ self.class.props.each{ |p|
75
+ @app.formatter(p).property( p ).parse( object, p, xml )
76
+ }
77
+ return object
78
+ end
79
+
80
+ # String representation of a resource
81
+ def to_s
82
+ "path #{self.class.mount_point}, service #{self.class.service}, model #{self.class.model}"
83
+ end
84
+
85
+ end
86
+
87
+ end
@@ -0,0 +1,92 @@
1
+ module RubyRest
2
+
3
+ module Webrick
4
+
5
+
6
+ # The Ruby-on-Rest Webrick adapter implementation
7
+ class Server < WEBrick::HTTPServer
8
+
9
+ attr_reader :app
10
+
11
+ # Builds a new Webrick adapter instance
12
+ # for the given application
13
+ def initialize( app )
14
+ super( :Port => app.config[:http_port] )
15
+ @app = app
16
+ servlet = RubyRest::Webrick::Servlet.new( self )
17
+ mount "/", servlet
18
+ end
19
+
20
+ # Starts the server
21
+ def up
22
+ [ "INT", "TERM" ].each { |signal|
23
+ trap( signal ) { shutdown }
24
+ }
25
+ start
26
+ end
27
+
28
+ end
29
+
30
+ # A REST servlet for Webrick adapter
31
+ class Servlet < WEBrick::HTTPServlet::AbstractServlet
32
+
33
+ # Builds a new servlet, taking the application from it
34
+ def initialize( server )
35
+ @app = server.app
36
+ end
37
+
38
+ # A single servlet instance will be used
39
+ # for all requests
40
+ def get_instance( server )
41
+ self
42
+ end
43
+
44
+ def decode_path( path )
45
+ path.gsub( "+", " ")
46
+ end
47
+
48
+ def args( request )
49
+ args = Hash.new
50
+ url_tokens = decode_path( request.path ).split( "/")
51
+ args[:target] = url_tokens[2] if url_tokens.length>2
52
+ args[:property] = url_tokens[3] if url_tokens.length>3
53
+ args[:path] = request.path
54
+ args[:body] = RubyRest::Atom::Document.new( request.body ) if request.body
55
+ return args
56
+ end
57
+
58
+ def do_GET( request, response )
59
+ params = args(request )
60
+ response.status = 200
61
+ xml = @app.retrieve( params )
62
+ response["content-type"]=params[:content_type]
63
+ xml.write( response.body )
64
+ end
65
+
66
+ def do_POST( request, response )
67
+ params = args(request )
68
+ response.status = 201
69
+ xml = @app.create( params )
70
+ response["content-type"]=params[:content_type]
71
+ xml.write( response.body )
72
+ end
73
+
74
+ def do_PUT( request, response )
75
+ params = args(request )
76
+ response.status = 200
77
+ xml = @app.update( params )
78
+ response["content-type"]=params[:content_type]
79
+ xml.write( response.body )
80
+ end
81
+
82
+ def do_DELETE( request, response )
83
+ params = args(request )
84
+ response.status = 200
85
+ @app.delete( params )
86
+ end
87
+
88
+ end
89
+
90
+ end
91
+
92
+ end
data/lib/rubyrest.rb CHANGED
@@ -3,23 +3,18 @@
3
3
  # Entry point to the framework.
4
4
  # Loads all the files under the 'rubyrest' subdirectory
5
5
  require "rubygems"
6
+ require "sequel"
7
+ require "sequel/postgres"
6
8
  require "extensions/all"
7
- require "builder"
8
9
  require "rexml/document"
9
10
  require "webrick"
11
+ require "find"
10
12
 
11
-
12
- dir = File.join( File.dirname( __FILE__ ), 'rubyrest' )
13
-
14
- require File.join( dir, "tools" )
15
- require File.join( dir, "atom" )
16
- require File.join( dir, "servlets" )
17
- require File.join( dir, "config" )
13
+ here = File.dirname( __FILE__ )
14
+ dir = File.join( here , 'rubyrest' )
15
+ require File.join( dir, "webrick" )
16
+ require File.join( dir, "resource" )
17
+ require File.join( dir, "application" )
18
18
  require File.join( dir, "engine" )
19
- require File.join( dir, "client" )
20
-
21
- module RubyRest #:nodoc:
22
- class << self
23
-
24
- end
25
- end
19
+ require File.join( dir, "atom" )
20
+ require File.join( dir, "client" )
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.1
3
3
  specification_version: 1
4
4
  name: rubyrest
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.0.5
7
- date: 2007-04-20 00:00:00 +02:00
6
+ version: 0.1.0
7
+ date: 2007-06-04 00:00:00 +02:00
8
8
  summary: REST framework for Ruby.
9
9
  require_paths:
10
10
  - lib
@@ -37,13 +37,12 @@ files:
37
37
  - doc/rdoc
38
38
  - lib/rubyrest
39
39
  - lib/rubyrest.rb
40
+ - lib/rubyrest/application.rb
40
41
  - lib/rubyrest/atom.rb
41
42
  - lib/rubyrest/client.rb
42
- - lib/rubyrest/config.rb
43
43
  - lib/rubyrest/engine.rb
44
- - lib/rubyrest/servlets.rb
45
- - lib/rubyrest/tools.rb
46
- - examples/hello.rb
44
+ - lib/rubyrest/resource.rb
45
+ - lib/rubyrest/webrick.rb
47
46
  test_files: []
48
47
 
49
48
  rdoc_options:
@@ -58,13 +57,10 @@ rdoc_options:
58
57
  - --inline-source
59
58
  - --exclude
60
59
  - lib/rubyrest.rb
61
- - --include
62
- - examples/*.rb
63
60
  extra_rdoc_files:
64
61
  - README
65
62
  - CHANGELOG
66
63
  - COPYING
67
- - examples/hello.rb
68
64
  executables:
69
65
  - rubyrest
70
66
  extensions: []
data/examples/hello.rb DELETED
@@ -1,57 +0,0 @@
1
- # Ruby-on-Rest HelloWorld application
2
- #
3
- #
4
- #
5
- module Acme
6
-
7
- module Hello
8
-
9
- # The configuration for the Acme::Hello service.
10
- # This is a simple service that does not need database
11
- # connectivity.
12
- class Config < RubyRest::SimpleConfig
13
-
14
- end
15
-
16
- # The dashboard that provides an entry point to the
17
- # application
18
- class Dashboard
19
-
20
- def self.rest_retrieve( principal )
21
- [ "welcomeservice" ]
22
- end
23
-
24
- end
25
-
26
- # The domain service that actually implements
27
- # 'business' logic. In this case, it's just going to say "Hello!"
28
- # by returning a HelloBean object
29
- class Welcomeservice
30
-
31
- # Returns a simple object that says hello
32
- # This is the method invoked by RubyRest::CRUDServlet
33
- # when it receives a GET request with no particular resource id
34
- def self.rest_retrieve( principal )
35
- HelloBean.new
36
- end
37
-
38
- end
39
-
40
- # The object that encapsulates the so sophisticated
41
- # message. By including RubyRest::Atom::Entry, we get some convenience
42
- # methods that help to provide an atom entry representation
43
- # of the bean, without too much effort.
44
- class HelloBean
45
- include RubyRest::Atom::DummyEntry
46
-
47
- # The hello message, included as a 'message'
48
- # node inside an Atom Entry content.
49
- def atom_content( builder )
50
- builder.message "Hello!"
51
- end
52
- end
53
-
54
- end
55
-
56
- end
57
-
@@ -1,80 +0,0 @@
1
- # RubyRest: $Id:$
2
- #
3
- #
4
- #
5
- module RubyRest
6
-
7
- # This class is meant to be subclassed with customized
8
- # behaviour that will be invoked by the engine at startup.
9
- # Subclasses can provide connectivity to popular database
10
- # frameworks such as ActiveRecord, Sequel or Og.
11
- #
12
- # Example:
13
- #
14
- # module MyService
15
- # class Config < RubyRest::SimpleConfig
16
- #
17
- # end
18
- # end
19
- #
20
- #
21
- class SimpleConfig
22
- include RubyRest::Tools
23
-
24
- # Initializes a new configuration with the specified
25
- # hash of data
26
- def initialize( hash )
27
- @hash = hash
28
- end
29
-
30
- # Overrides the specified configuration option
31
- # with its new value
32
- def []=( name, value )
33
- @hash[ name ] = value
34
- end
35
-
36
- # Returns a given configuration option value
37
- def [](name)
38
- raise error( 000, name ) if !has( name )
39
- return @hash[ name ]
40
- end
41
-
42
- # Returns true if the specified name matches
43
- # a valid configuration option
44
- def has( name )
45
- @hash[ name ] != nil
46
- end
47
-
48
- # Dumps all the configuration options
49
- def to_s
50
- @hash.each{ |k,v| puts "key: #{k}, value: #{v}" }
51
- end
52
-
53
- end
54
-
55
- # Specialization of SimpleConfig that provides
56
- # hooks for database initialization during startup
57
- class DatabaseConfig < SimpleConfig
58
-
59
- # Connects and returns a database instance.
60
- #
61
- # This method
62
- # will delegate to a more specialized method, according to the
63
- # :adapter config option
64
- def connect_to_database
65
- adapter_method = "#{self[:adapter]}_connect"
66
- error( 004, self, adapter_method ) if !self.respond_to?( adapter_method )
67
- @db = self.method( adapter_method ).call
68
- error( 005, self, adapter_method ) if @db == nil
69
- end
70
-
71
- # This method must be implemented in subclasses
72
- # Intentionnaly left empty
73
- def init_database
74
-
75
- end
76
-
77
- end
78
-
79
-
80
- end