actionservice 0.2.99

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