rubyrest 0.0.5 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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