rubyrest 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,8 +1,21 @@
1
+ == What's next?
2
+
3
+ * Introduce the concept of 'security authority' so that multiple deployed instances of rubyrest can be federated by a single authentication and authorization service.
4
+ * Use mongrel as the HTTP server implementation, instead of WEBrick
5
+ * Refactor code, style it more 'a la' Ruby.
6
+ * Provide more complex examples, such as Database Configurations
7
+
8
+ == Release 0.0.4
9
+
10
+ * Module RubyRest::Client has been redesigned into class RubyRest::Client::Default which offers a higher level api by translating create, retrieve, update and delete method calls into proper HTTP GET, POST, PUT and DELETE requests.
11
+ * Engine configurations are now externalized so they can be provided programmatically as Hashes or loaded from YAML files.
12
+ * The rubyrest command line now supports different deployment environments (dev, live)
13
+
1
14
  == Release 0.0.3
2
15
 
3
16
  * Added module RubyRest::Client, providing a convenience client to REST APIs deployed with Ruby-on-Rest
4
17
  * Improved Atom representation of resources (feeds, entries and service documents)
5
- * Dashboard (service document) can now be customized by developpers by implementing a class with name Dashboard.
18
+ * Dashboard (service document) can now be customized by developers by implementing a class with name Dashboard.
6
19
 
7
20
  == Release 0.0.2
8
21
 
data/README CHANGED
@@ -30,15 +30,27 @@ If you have any comments or suggestions please send an email to pedro dot gutier
30
30
 
31
31
  Please have a look at the examples provided, they are simple enough to let you grasp how rubyrest works.
32
32
 
33
- === Starting and stopping the service
33
+ === Starting the service
34
34
 
35
35
  Ruby-on-Rest provides a shell command. Open your console, and type the following:
36
36
 
37
- rubyrest start|stop <my_service> [<my_service_module>]
37
+ rubyrest dev <my_service> (for development deployment)
38
+ rubyrest live <my_service> (for live deployment)
38
39
 
39
- Ruby-on-Rest can also be embedded in ruby code. This is useful for testing purposes:
40
+ This will first look at a YAML file called <my_service>_dev.yaml or <my_service>_live.yaml under the
41
+ current path.
40
42
 
41
- engine = RubyRest::Engine.new( <my_service>, <my_service_module> )
43
+ Ruby-on-Rest can also be embedded in ruby code. This is useful for testing purposes:
44
+
45
+ config = {
46
+ "service" => "hello",
47
+ "prefix" => "acme",
48
+ "serviceport" => 9003
49
+ "daemon" => true
50
+ "entities" => [ "welcomeservice" ]
51
+ }
52
+
53
+ engine = RubyRest::Engine.new( config )
42
54
  engine.start
43
55
  # ...
44
56
  # do some http calls here
@@ -48,7 +60,8 @@ Ruby-on-Rest can also be embedded in ruby code. This is useful for testing purpo
48
60
 
49
61
  === Configuring your service
50
62
 
51
- Ruby-on-Rest will try to load a file name <my_service>.rb which must provide access to
52
- the service configuration, service and model.
63
+ Ruby-on-Rest will try to load a file name <my_service>.rb which provides the implementation of the service.
64
+
65
+
53
66
 
54
67
 
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  NAME = "rubyrest"
9
- VERS = "0.0.3"
9
+ VERS = "0.0.4"
10
10
  CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
11
11
  RDOC_OPTS = ['--quiet', '--title', "Ruby-on-Rest: A simple REST framework for Ruby",
12
12
  "--opname", "index.html",
data/bin/rubyrest CHANGED
@@ -7,20 +7,24 @@ require 'rubygems'
7
7
  require 'rubyrest'
8
8
 
9
9
  service = ARGV[1]
10
- prefix = ARGV[2]
11
- action = ARGV[0]
10
+ deploy_mode = ARGV[0]
12
11
 
13
- if action == nil or ( action != "start" and action != "stop" ) or service == nil
14
- puts "Usage: rubyrest start|stop <your_service> "
12
+ if service == nil or deploy_mode == nil
13
+ puts "Usage: rubyrest dev|live <your_service>"
15
14
  puts "Ruby-on-Rest: Simple REST for Ruby."
16
15
  puts
17
16
  puts "Examples:"
18
- puts " rubyrest start grape"
19
- puts " rubyrest stop grape"
17
+ puts " rubyrest dev grape"
18
+ puts " rubyrest live grape"
20
19
  puts
21
20
  puts "For more information see http://rubyrest.rubyforge.org"
22
21
  else
23
- engine = RubyRest::Engine.new( service, prefix )
24
- engine.method( action ).call
22
+ # load the yaml file for the
23
+ # deploy specific configuration, and build a hash out of it
24
+ params = YAML::load_file( "#{service}_#{deploy_mode}.yaml" )
25
+ params[ "service" ] = service
26
+
27
+ engine = RubyRest::Engine.new( params )
28
+ engine.start
25
29
  end
26
30
 
data/examples/hello.rb CHANGED
@@ -11,18 +11,18 @@ module Acme
11
11
  # connectivity.
12
12
  class Config < RubyRest::SimpleConfig
13
13
 
14
- # Inits the internal hash of
15
- # configuration options. This is the minimal expression
16
- # of a Ruby-on-Rest configuration hash.
17
- def initialize
18
- @hash = {
19
- :servicemodel => [ "welcomeservice" ],
20
- :serviceport => 9001
21
- }
22
- end
23
-
24
14
  end
25
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
26
  # The domain service that actually implements
27
27
  # 'business' logic. In this case, it's just going to say "Hello!"
28
28
  # by returning a HelloBean object
data/lib/rubyrest/atom.rb CHANGED
@@ -167,6 +167,13 @@ module RubyRest
167
167
  def id
168
168
  text( "/entry/moodisland:content/id" )
169
169
  end
170
+
171
+ # Overrides the default implementation
172
+ # by returning a new Ruby-on-Rest Atom Document
173
+ def clone
174
+ self.class.new self.to_s
175
+ end
176
+
170
177
  end
171
178
 
172
179
  end
@@ -4,69 +4,131 @@ module RubyRest
4
4
  # to REST services offered by Ruby-on-REST.
5
5
  module Client
6
6
 
7
- # Builds a headers hash, with the specified
8
- # authorization token if not nil
9
- def prepare_headers( auth = nil )
10
- headers = { "Content-Type" => "text/xml; charset=utf-8" }
11
- headers[ "token" ] = auth if auth != nil
12
- return headers
13
- end
14
-
15
- # Reusable method that builds an Atom entry out of the specified hash of data
16
- def hash2entry( data )
17
- doc = RubyRest::Atom::Entry::Document.new
18
- entry = REXML::Element.new( "entry", doc )
19
- content = REXML::Element.new( "content", entry )
20
- data.each { |name,value|
21
- body = REXML::Element.new( name.to_s, content )
22
- body.text = value
23
- }
24
- return doc
25
- end
26
-
27
- # Parses the response body string as a Ruby-on-Rest Entry document,
28
- def str2entry( rsp )
29
- begin
30
- RubyRest::Atom::Entry::Document.new( rsp.body ) if response.body
31
- rescue => e
32
- return nil
7
+ # Default client for web services deployed with
8
+ # Ruby-on-Rest. Translates create, retrieve, update and
9
+ # delete methods into POST, GET, PUT and DELETE http requests
10
+ class Default
11
+
12
+ # Configures the server name and port
13
+ def self.with_server name, port
14
+ @host = name
15
+ @port = port
33
16
  end
17
+
18
+ # Returns the hostname of the service to
19
+ # connect to
20
+ def self.host
21
+ @host
22
+ end
23
+
24
+ # Returns the port number on which to
25
+ # connect to
26
+ def self.port
27
+ @port
28
+ end
29
+
30
+ # Converts the specified hash of data into a
31
+ # query string, then performs a GET http request.
32
+ # The response body is returned as an an Atom document if
33
+ # the response status code is 200.
34
+ def retrieve( path, data, api_key )
35
+ path << to_query_string( data ) if data
36
+ headers = prepare_headers( api_key )
37
+ rsp = http.get( path, headers )
38
+ return to_xml( rsp ) if rsp.code.to_i == 200
39
+ end
40
+
41
+ # Converts the specified hash of data into a
42
+ # simplified Atom Entry, then performs a POST http request.
43
+ # The response body is returned as an an Atom Entry if
44
+ # the response status code is 201.
45
+ def create( path, data, api_key )
46
+ body = nil
47
+ body = hash2entry( data ).to_s if data != nil
48
+ headers = prepare_headers( api_key )
49
+ rsp = http.post( path, body, headers )
50
+ return to_xml( rsp ) if rsp.code.to_i == 201
51
+ end
52
+
53
+ # Converts the specified hash of data into a
54
+ # simplified Atom Entry, then performs a PUT http request.
55
+ # The response body is returned as an an Atom Entry if
56
+ # the response status code is 200.
57
+ def update( path, data, api_key )
58
+ body = nil
59
+ body = hash2entry( data ).to_s if data != nil
60
+ headers = prepare_headers( api_key )
61
+ rsp = http.put( path, body, headers )
62
+ return to_xml( rsp ) if rsp.code.to_i == 200
63
+ end
64
+
65
+ # Converts the specified hash of data into a
66
+ # query string, then performs a DELETE http request.
67
+ # This method simply returns the response status code
68
+ def delete( path, data, api_key )
69
+ path << to_query_string( data ) if data
70
+ headers = prepare_headers( api_key )
71
+ rsp = http.delete( path, headers )
72
+ rsp.code.to_i
73
+ end
74
+
75
+ # Convenience method that returns the
76
+ # service document from the service endpoint
77
+ def dashboard( api_key )
78
+ retrieve( "/", nil, api_key )
79
+ end
80
+
81
+ # Convenience method that returns a new HTTP object
82
+ # for each call
83
+ def http
84
+ Net::HTTP.new( self.class.host, self.class.port )
85
+ end
86
+
87
+ # Builds a headers hash, with the specified
88
+ # authorization token if not nil
89
+ def prepare_headers( api_key = nil )
90
+ headers = { "Content-Type" => "text/xml; charset=utf-8" }
91
+ headers[ "token" ] = api_key if api_key != nil
92
+ return headers
93
+ end
94
+
95
+ # Converts the specified hash of data into a simplified
96
+ # Atom Entry document.
97
+ def hash2entry( data )
98
+ doc = RubyRest::Atom::Entry::Document.new
99
+ entry = REXML::Element.new( "entry", doc )
100
+ content = REXML::Element.new( "content", entry )
101
+ data.each { |name,value|
102
+ body = REXML::Element.new( name.to_s, content )
103
+ body.text = value
104
+ }
105
+ return doc
106
+ end
107
+
108
+ # Parses the response body string as a Ruby-on-Rest XML Document,
109
+ # which can be a Feed or Entry, or Service Document
110
+ def to_xml( rsp )
111
+ begin
112
+ RubyRest::Atom::Entry::Document.new( rsp.body ) if rsp.body
113
+ rescue => e
114
+ puts "unable to parse response body: " + e.message
115
+ puts "---- response body ----"
116
+ puts rsp.body
117
+ puts "-----------------------"
118
+ return nil
119
+ end
120
+ end
121
+
122
+ # Reusable method that creates a query string
123
+ # with the specified hash of data
124
+ def to_query_string( data )
125
+ qs = "?"
126
+ params.each{ |k,v| qs << "#{k}=#{v}&" }
127
+ qs.chop!
128
+ end
129
+
34
130
  end
35
131
 
36
- # Reusable method that creates a query string
37
- # with the specified hash of data
38
- def to_query_string( data )
39
- qs = "?"
40
- params.each{ |k,v| qs << "#{k}=#{v}&" }
41
- qs.chop!
42
- end
43
-
44
- # Performs a POST request and returns the raw response object
45
- # The data (a hash of name,value pairs) is converted to an
46
- # simplified Atom Entry
47
- def post( server, port, path, data, token )
48
- body = nil
49
- body = hash2entry( data ).to_s if data != nil
50
- headers = prepare_headers( token )
51
- rsp = Net::HTTP.new( server, port ).post( path, body, headers )
52
- [ rsp.code.to_i, str2entry( rsp ) ]
53
- end
54
-
55
- # Performs a GET request and returns the raw response object
56
- # The data (a hash of name,value pairs) is converted to a query
57
- # string, then concatenated to the path.
58
- def get( server, port, path, data, token )
59
- path << to_query_string( data ) if data
60
- headers = prepare_headers( token )
61
- rsp = Net::HTTP.new( server, port ).get( path, headers )
62
- [ rsp.code.to_i, str2entry( rsp ) ]
63
- end
64
-
65
-
66
-
67
132
  end
68
133
 
69
-
70
-
71
-
72
134
  end
@@ -13,11 +13,7 @@ module RubyRest
13
13
  #
14
14
  # module MyService
15
15
  # class Config < RubyRest::SimpleConfig
16
- # def initialize
17
- # @hash = {
18
- # ... my config here ..
19
- # }
20
- # end
16
+ #
21
17
  # end
22
18
  # end
23
19
  #
@@ -25,6 +21,12 @@ module RubyRest
25
21
  class SimpleConfig
26
22
  include RubyRest::Tools
27
23
 
24
+ # Initializes a new configuration with the specified
25
+ # hash of data
26
+ def initialize( hash )
27
+ @hash = hash
28
+ end
29
+
28
30
  # Overrides the specified configuration option
29
31
  # with its new value
30
32
  def []=( name, value )
@@ -45,7 +47,7 @@ module RubyRest
45
47
 
46
48
  # Dumps all the configuration options
47
49
  def to_s
48
- @hash.each{ |k,v| puts "#{k} = #{v}" }
50
+ @hash.each{ |k,v| puts "key: #{k}, value: #{v}" }
49
51
  end
50
52
 
51
53
  end
@@ -60,7 +62,7 @@ module RubyRest
60
62
  # will delegate to a more specialized method, according to the
61
63
  # :adapter config option
62
64
  def connect_to_database
63
- adapter_method = "#{@hash[:dbadapter]}_connect"
65
+ adapter_method = "#{self[:adapter]}_connect"
64
66
  error( 004, self, adapter_method ) if !self.respond_to?( adapter_method )
65
67
  @db = self.method( adapter_method ).call
66
68
  error( 005, self, adapter_method ) if @db == nil
@@ -14,14 +14,18 @@ module RubyRest
14
14
  # engine configuration
15
15
  attr_reader :config
16
16
 
17
- # Creates a new RubyRest engine, for the service
18
- # and service prefix
19
- def initialize( service, prefix = nil )
20
- @service = service
21
- @prefix = prefix
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 ]
22
26
  service_module = to_module_name( @prefix, @service )
23
27
  require @service
24
- @config = to_class( service_module, "config" ).new
28
+ @config = to_class( service_module, "config" ).new( params )
25
29
  @config[ :servicemodule ] = service_module
26
30
  end
27
31
 
@@ -31,7 +35,7 @@ module RubyRest
31
35
  # 2. launch the webserver, in daemon mode unless false is
32
36
  # specified in the configuration
33
37
  def start
34
- configure_database if @config.has( :dbadapter )
38
+ configure_database if @config.has( :adapter )
35
39
  @server = RubyRest::Server.new( @config )
36
40
  @server.mount "/", CRUDServlet
37
41
  if @config.has( :daemon ) and @config[ :daemon ] == false
@@ -51,7 +55,7 @@ module RubyRest
51
55
  def configure_database
52
56
  @config.connect_to_database
53
57
  @config.setup_persistence
54
- if @config[ :dbdestroy ] == true
58
+ if @config[ :destroy ] == true
55
59
  @config.init_schema
56
60
  @config.load_initial_data
57
61
  end
@@ -38,7 +38,11 @@ module RubyRest
38
38
  @model = params[1]
39
39
  @id = params[2]
40
40
  @property = params[3]
41
- @body = REXML::Document.new( request.body ) if request.body != nil
41
+ begin
42
+ @body = REXML::Document.new( request.body ) if request.body != nil
43
+ rescue => e
44
+ puts "unable to parse request body: #{request.body}"
45
+ end
42
46
  end
43
47
 
44
48
  def resolve_custom_method
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.3
7
- date: 2007-04-08 00:00:00 +02:00
6
+ version: 0.0.4
7
+ date: 2007-04-15 00:00:00 +02:00
8
8
  summary: REST framework for Ruby.
9
9
  require_paths:
10
10
  - lib