rubyrest 0.0.3 → 0.0.4

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