actionservice 0.2.99

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG ADDED
@@ -0,0 +1,3 @@
1
+ *0.2*
2
+
3
+ * First release
data/HACKING ADDED
@@ -0,0 +1,39 @@
1
+ == Coding Style
2
+
3
+ Please try to follow Rails conventions and idioms.
4
+
5
+
6
+ == Concepts
7
+
8
+ * Service
9
+ A service contains zero or more exports (methods)
10
+
11
+ * Container
12
+ A container contains zero or more services
13
+
14
+ * Router
15
+ A router takes raw wire requests, decodes them, performs the invocation on
16
+ the service, and generates raw wire responses from the invocation result.
17
+ A router is mixed into a container class.
18
+
19
+ * Protocol
20
+ A protocol implementation implements the unmarshaling and marshaling of
21
+ raw wire requests and responses. Registers with router.
22
+
23
+
24
+ == Action Pack Integration
25
+
26
+ For Action Pack, the ActionController is both container and router, and also contains
27
+ the protocol implementations.
28
+
29
+
30
+ == Adding support for a new protocol
31
+
32
+ 1. Add an ActionService::Protocol::YourProtocol module and any classes you need to
33
+ perform unmarshaling/marshaling of protocol requests. See the SOAP implementation
34
+ for an example of a complex mapping, and also see
35
+ ActionService::Protocol::AbstractProtocol for the methods you need to implement.
36
+
37
+ 2. Add unit tests for your new protocol. Be sure to test using a Action Pack test request
38
+ duplicating how the real requests will arrive and verify that mapping to and from Ruby
39
+ types works correctly.
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (C) 2005 Leon Breedt
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
data/README ADDED
@@ -0,0 +1,36 @@
1
+ = Action Service -- Web service integration with Action Pack
2
+
3
+ FIXME
4
+
5
+ == Dependencies
6
+
7
+ Action Service requires that the Action Pack is either available to be required immediately
8
+ or is accessible as a GEM.
9
+
10
+ It also requires a version of Ruby that includes SOAP support in the standard library. At
11
+ least version 1.8.2 final is recommended.
12
+
13
+
14
+ == Download
15
+
16
+
17
+ FIXME
18
+
19
+
20
+ == Installation
21
+
22
+ You can install Action Service with the following command.
23
+
24
+ % [sudo] ruby install.rb
25
+
26
+ from its distribution directory.
27
+
28
+
29
+ == License
30
+
31
+ Action Service is released under the MIT license.
32
+
33
+
34
+ == Support
35
+
36
+ FIXME
data/Rakefile ADDED
@@ -0,0 +1,121 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rake/testtask'
4
+ require 'rake/rdoctask'
5
+ require 'rake/packagetask'
6
+ require 'rake/gempackagetask'
7
+ require 'rake/contrib/rubyforgepublisher'
8
+
9
+ PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
+ PKG_NAME = 'actionservice'
11
+ PKG_VERSION = '0.2.99' + PKG_BUILD
12
+ PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
+
14
+ desc "Default Task"
15
+ task :default => [ :test ]
16
+
17
+
18
+ # Run the unit tests
19
+ Rake::TestTask.new { |t|
20
+ t.libs << "test"
21
+ t.pattern = 'test/*_test.rb'
22
+ t.verbose = true
23
+ }
24
+
25
+
26
+ # Generate the RDoc documentation
27
+ Rake::RDocTask.new { |rdoc|
28
+ rdoc.rdoc_dir = 'doc'
29
+ rdoc.title = "Action Service -- Web services for Action Pack"
30
+ rdoc.options << '--line-numbers --inline-source --main README'
31
+ rdoc.rdoc_files.include('README', 'CHANGELOG')
32
+ rdoc.rdoc_files.include('lib/action_service.rb')
33
+ rdoc.rdoc_files.include('lib/action_service/*.rb')
34
+ rdoc.rdoc_files.include('lib/action_service/protocol/*.rb')
35
+ rdoc.rdoc_files.include('lib/action_service/router/*.rb')
36
+ }
37
+
38
+
39
+ # Create compressed packages
40
+ spec = Gem::Specification.new do |s|
41
+ s.platform = Gem::Platform::RUBY
42
+ s.name = PKG_NAME
43
+ s.summary = "Web service support for Action Pack."
44
+ s.description = %q{Adds WSDL/SOAP and XML-RPC web service support to Action Pack}
45
+ s.version = PKG_VERSION
46
+
47
+ s.author = "Leon Breedt"
48
+ s.email = "bitserf@gmail.com"
49
+ s.rubyforge_project = "actionservice"
50
+ s.homepage = "http://rubyforge.org/projects/actionservice"
51
+
52
+ s.add_dependency('actionpack', '>= 1.4.0')
53
+
54
+ s.has_rdoc = true
55
+ s.requirements << 'none'
56
+ s.require_path = 'lib'
57
+ s.autorequire = 'action_service'
58
+
59
+ s.files = [ "Rakefile", "setup.rb", "README", "TODO", "HACKING", "CHANGELOG", "MIT-LICENSE" ]
60
+ s.files = s.files + Dir.glob( "examples/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
61
+ s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
62
+ s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
63
+ end
64
+ Rake::GemPackageTask.new(spec) do |p|
65
+ p.gem_spec = spec
66
+ p.need_tar = true
67
+ p.need_zip = true
68
+ end
69
+
70
+
71
+ desc "Publish the beta gem"
72
+ task :pgem => [:package] do
73
+ # Rake::SshFilePublisher.new("davidhh@comox.textdrive.com", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
74
+ end
75
+
76
+
77
+ desc "Publish the API documentation"
78
+ task :pdoc => [:rdoc] do
79
+ # Rake::SshDirPublisher.new("davidhh@comox.textdrive.com", "public_html/am", "doc").upload
80
+ end
81
+
82
+
83
+ desc "Publish to RubyForge"
84
+ task :rubyforge do
85
+ Rake::RubyForgePublisher.new('actionservice', 'ljb').upload
86
+ end
87
+
88
+
89
+ desc "Count lines in the main rake file"
90
+ task :lines do
91
+ lines = 0
92
+ codelines = 0
93
+ prefix = File.join(File.dirname(__FILE__), 'lib')
94
+ puts "Per File:"
95
+ %w{
96
+ action_service
97
+ action_service/protocol
98
+ action_service/router
99
+ }.each do |dir|
100
+ Dir.foreach(File.join(prefix, dir)) { |file_name|
101
+ next unless file_name =~ /.*rb$/
102
+ full_file_name = File.join(prefix, dir, file_name)
103
+
104
+ f = File.open(full_file_name)
105
+
106
+ file_lines = 0
107
+ file_codelines = 0
108
+ while line = f.gets
109
+ file_lines += 1
110
+ next if line =~ /^\s*$/
111
+ next if line =~ /^\s*#/
112
+ file_codelines += 1
113
+ end
114
+ puts " #{File.join('lib', dir, file_name)}: Lines #{file_lines}, LOC #{file_codelines}"
115
+ lines += file_lines
116
+ codelines += file_codelines
117
+ }
118
+ end
119
+ puts "Total:"
120
+ puts " Lines #{lines}, LOC #{codelines}"
121
+ end
data/TODO ADDED
@@ -0,0 +1,25 @@
1
+ = Features Remaining
2
+ - XML-RPC support
3
+ - Support for ActiveRecord model classes as structure types as well, since
4
+ we can reflect all the details to do proper mapping from model classes.
5
+
6
+ = Ideas
7
+ - <nextangle> Support a second dispatching mechanism, where incoming
8
+ operation requests are mapped directly to a controller action.
9
+
10
+ Advantages: No seperate API service class, the controller becomes the
11
+ service class.
12
+
13
+ Possible approaches:
14
+ Create a new router that maps an 'api' action to do dispatching using
15
+ itself as the target service.
16
+
17
+ This dispatching would:
18
+
19
+ * Unpack request parameters into @params
20
+ * Execute the action
21
+ * Use the return value of the action to send back to the client
22
+
23
+ = Warts
24
+ - Don't have clean way to go from SOAP Class object to the xsd:NAME type
25
+ string
@@ -0,0 +1,121 @@
1
+ = Google Service example
2
+
3
+
4
+ This example shows how one would implement an API like Google
5
+ Search, that uses lots of structured types.
6
+
7
+
8
+ = Testing
9
+
10
+ 1. Ensure you have the 'actionservice' Gem installed. You can generate it using
11
+ this command:
12
+
13
+ $ rake package
14
+
15
+ 2. Copy lib/google_search_service.rb and app/controllers/search_controller.rb
16
+ into a Rails project.
17
+
18
+ 3. Edit config/environment.rb, and add the following line after the rest of the
19
+ require_gem statements:
20
+
21
+ require_gem 'actionservice'
22
+
23
+ 4. Go to the url http://URL/search/wsdl in a browser, and check that it looks
24
+ correct.
25
+
26
+ You can compare it to Google's hand-coded WSDL at http://api.google.com/GoogleSearch.wsdl
27
+ and see how close (or not) the generated version is.
28
+
29
+ Note that I used GoogleSearch as the canonical "best practice"
30
+ interoperable example, which might explain extreme similarities :)
31
+
32
+ 5. Test that it works with .NET (Mono in this example):
33
+
34
+ $ wget http://APP/search/wsdl
35
+ $ mv wsdl GoogleSearch.wsdl
36
+ $ wsdl -out:GoogleSearch.cs GoogleSearch.wsdl
37
+
38
+ Add these lines to the GoogleSearchService class body (be mindful of the
39
+ wrapping):
40
+
41
+ public static void Main(string[] args)
42
+ {
43
+ GoogleSearchResult result;
44
+ GoogleSearchService service;
45
+
46
+ service = new GoogleSearchService();
47
+ result = service.doGoogleSearch("myApiKey", "my query", 10, 30, true, "restrict", false, "lr", "ie", "oe");
48
+ System.Console.WriteLine("documentFiltering: {0}", result.documentFiltering);
49
+ System.Console.WriteLine("searchComments: {0}", result.searchComments);
50
+ System.Console.WriteLine("estimatedTotalResultsCount: {0}", result.estimatedTotalResultsCount);
51
+ System.Console.WriteLine("estimateIsExact: {0}", result.estimateIsExact);
52
+ System.Console.WriteLine("resultElements:");
53
+ foreach (ResultElement element in result.resultElements) {
54
+ System.Console.WriteLine("\tsummary: {0}", element.summary);
55
+ System.Console.WriteLine("\tURL: {0}", element.URL);
56
+ System.Console.WriteLine("\tsnippet: {0}", element.snippet);
57
+ System.Console.WriteLine("\ttitle: {0}", element.title);
58
+ System.Console.WriteLine("\tcachedSize: {0}", element.cachedSize);
59
+ System.Console.WriteLine("\trelatedInformationPresent: {0}", element.relatedInformationPresent);
60
+ System.Console.WriteLine("\thostName: {0}", element.hostName);
61
+ System.Console.WriteLine("\tdirectoryCategory: {0}", element.directoryCategory.fullViewableName);
62
+ System.Console.WriteLine("\tdirectoryTitle: {0}", element.directoryTitle);
63
+ }
64
+ System.Console.WriteLine("searchQuery: {0}", result.searchQuery);
65
+ System.Console.WriteLine("startIndex: {0}", result.startIndex);
66
+ System.Console.WriteLine("endIndex: {0}", result.endIndex);
67
+ System.Console.WriteLine("searchTips: {0}", result.searchTips);
68
+ System.Console.WriteLine("directoryCategories:");
69
+ foreach (DirectoryCategory cat in result.directoryCategories) {
70
+ System.Console.WriteLine("\t{0} ({1})", cat.fullViewableName, cat.specialEncoding);
71
+ }
72
+ System.Console.WriteLine("searchTime: {0}", result.searchTime);
73
+ }
74
+
75
+ Now compile and run:
76
+
77
+ $ mcs -reference:System.Web.Services GoogleSearch.cs
78
+ $ mono GoogleSearch.exe
79
+
80
+
81
+ If you had the application running (on the same host you got
82
+ the WSDL from), you should see something like this (values will match up
83
+ with those in lib/google_search_service.rb):
84
+
85
+
86
+ documentFiltering: True
87
+ searchComments:
88
+ estimatedTotalResultsCount: 322000
89
+ estimateIsExact: False
90
+ resultElements:
91
+ summary: ONlamp.com: Rolling with Ruby on Rails
92
+ URL: http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html
93
+ snippet: Curt Hibbs shows off Ruby on Rails by building a simple ...
94
+ title: Teh Railz0r
95
+ cachedSize: Almost no lines of code!
96
+ relatedInformationPresent: True
97
+ hostName: rubyonrails.com
98
+ directoryCategory: Web Development
99
+ directoryTitle:
100
+ searchQuery: http://www.google.com/search?q=ruby+on+rails
101
+ startIndex: 10
102
+ endIndex: 40
103
+ searchTips: "on" is a very common word and was not included in your search [details]
104
+ directoryCategories:
105
+ Web Development (UTF-8)
106
+ Programming (US-ASCII)
107
+ searchTime: 1E-06
108
+
109
+
110
+ Also, if an API method throws an exception, it will be sent back to the
111
+ caller in SOAP exception format, so they'll get an exception thrown on
112
+ their side with a meaningful error message.
113
+
114
+ If you don't like this behaviour, you can do:
115
+
116
+ class MyService < ActionService::Base
117
+ exception_reporting false
118
+ end
119
+
120
+ 6. Crack open a beer. Publishing APIs for working with the same model as
121
+ your Rails web app should be easy from now on :)
@@ -0,0 +1,8 @@
1
+ require 'google_search_service'
2
+
3
+ class SearchController < ApplicationController
4
+ wsdl_service_name 'GoogleSearch'
5
+ service :beta3, GoogleSearchService.new
6
+
7
+ # self.action_service_debugging = true
8
+ end
@@ -0,0 +1,90 @@
1
+ require 'action_service'
2
+
3
+ class DirectoryCategory < ActionService::Struct
4
+ member :fullViewableName, String
5
+ member :specialEncoding, String
6
+ end
7
+
8
+ class ResultElement < ActionService::Struct
9
+ member :summary, String
10
+ member :URL, String
11
+ member :snippet, String
12
+ member :title, String
13
+ member :cachedSize, String
14
+ member :relatedInformationPresent, TrueClass
15
+ member :hostName, String
16
+ member :directoryCategory, DirectoryCategory
17
+ member :directoryTitle, String
18
+ end
19
+
20
+ class GoogleSearchResult < ActionService::Struct
21
+ member :documentFiltering, TrueClass
22
+ member :searchComments, String
23
+ member :estimatedTotalResultsCount, Integer
24
+ member :estimateIsExact, TrueClass
25
+ member :resultElements, [ResultElement]
26
+ member :searchQuery, String
27
+ member :startIndex, Integer
28
+ member :endIndex, Integer
29
+ member :searchTips, String
30
+ member :directoryCategories, [DirectoryCategory]
31
+ member :searchTime, Float
32
+ end
33
+
34
+ class GoogleSearchService < ActionService::Base
35
+ export_name_mangling false
36
+
37
+ def doGetCachedPage(key, url)
38
+ "<html><body>i am a cached page</body></html>"
39
+ end
40
+
41
+ def doSpellingSuggestion(key, phrase)
42
+ "Did you mean 'teh'?"
43
+ end
44
+
45
+ def doGoogleSearch(key, q, start, maxResults, filter, restrict, safeSearch, lr, ie, oe)
46
+ resultElement = ResultElement.new
47
+ resultElement.summary = "ONlamp.com: Rolling with Ruby on Rails"
48
+ resultElement.URL = "http://www.onlamp.com/pub/a/onlamp/2005/01/20/rails.html"
49
+ resultElement.snippet = "Curt Hibbs shows off Ruby on Rails by building a simple application that requires " +
50
+ "almost no Ruby experience. ... Rolling with Ruby on Rails. ..."
51
+ resultElement.title = "Teh Railz0r"
52
+ resultElement.cachedSize = "Almost no lines of code!"
53
+ resultElement.relatedInformationPresent = true
54
+ resultElement.hostName = "rubyonrails.com"
55
+ resultElement.directoryCategory = category("Web Development", "UTF-8")
56
+
57
+ result = GoogleSearchResult.new
58
+ result.documentFiltering = filter
59
+ result.searchComments = ""
60
+ result.estimatedTotalResultsCount = 322000
61
+ result.estimateIsExact = false
62
+ result.resultElements = [resultElement]
63
+ result.searchQuery = "http://www.google.com/search?q=ruby+on+rails"
64
+ result.startIndex = start
65
+ result.endIndex = start + maxResults
66
+ result.searchTips = "\"on\" is a very common word and was not included in your search [details]"
67
+ result.searchTime = 0.000001
68
+
69
+ # For Mono, we have to clone objects if they're referenced by more than one place, otherwise
70
+ # the Ruby SOAP collapses them into one instance and uses references all over the
71
+ # place, confusing Mono
72
+ result.directoryCategories = [
73
+ category("Web Development", "UTF-8"),
74
+ category("Programming", "US-ASCII"),
75
+ ]
76
+
77
+ result
78
+ end
79
+
80
+ def category(name, encoding)
81
+ cat = DirectoryCategory.new
82
+ cat.fullViewableName = name.dup
83
+ cat.specialEncoding = encoding.dup
84
+ cat
85
+ end
86
+
87
+ export :doGetCachedPage, :returns => [String], :expects => [String, String]
88
+ export :doGetSpellingSuggestion, :returns => [String], :expects => [String, String]
89
+ export :doGoogleSearch, :returns => [GoogleSearchResult], :expects => [String, String, Integer, Integer, TrueClass, String, TrueClass, String, String, String]
90
+ end