actionservice 0.2.100 → 0.2.102

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
+ TBD
2
+
3
+ * First public release
data/README CHANGED
@@ -1,29 +1,54 @@
1
- = Action Service -- Web service integration with Action Pack
1
+ = Action Service -- Serving APIs on rails
2
+
3
+ Action Service provides a way to publish interoperablel web service APIs with
4
+ Rails without wasting time delving into protocol details.
5
+
6
+
7
+ == Features
8
+
9
+ * SOAP RPC protocol support
10
+ * Dynamic WSDL generation
11
+ * XML-RPC protocol support
12
+ * Strong type signature hints to improve interoperability with static
13
+ languages
14
+ * Using Active Record derivatives in return signatures automatically generates
15
+ a structured type equivalent that can be sent over the wire
16
+
17
+
18
+ == Integration with Action Pack
19
+
20
+ Action Service can be integrated in two different dispatching modes, _Direct_ and
21
+ _Delegated_.
22
+
23
+
24
+ * _Direct_ mode refers to a dispatching mode where one controller represents a
25
+ single API service, and actions in the controller represent API methods. This is
26
+ the default mode.
27
+ * _Delegated_ mode refers to a dispatching mode where a controller is a
28
+ container for one or more API services, and an action on the controller
29
+ serves as the entry point for an associated service.
2
30
 
3
- FIXME
4
31
 
5
32
  == Dependencies
6
33
 
7
- Action Service requires that the Action Pack is either available to be required immediately
8
- or is accessible as a GEM.
34
+ Action Service requires that the Action Pack and Active Record are either
35
+ available to be required immediately or are accessible as GEMs.
9
36
 
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.
37
+ It also requires a version of Ruby that includes SOAP support in the standard
38
+ library. At least version 1.8.2 final (2004-12-25) of Ruby is recommended.
12
39
 
13
40
 
14
41
  == Download
15
42
 
16
-
17
- FIXME
43
+ The latest Action Service version can be downloaded from
44
+ http://rubyforge.org/projects/actionservice
18
45
 
19
46
 
20
47
  == Installation
21
48
 
22
49
  You can install Action Service with the following command.
23
50
 
24
- % [sudo] ruby install.rb
25
-
26
- from its distribution directory.
51
+ % [sudo] ruby setup.rb
27
52
 
28
53
 
29
54
  == License
@@ -33,4 +58,6 @@ Action Service is released under the MIT license.
33
58
 
34
59
  == Support
35
60
 
36
- FIXME
61
+ The Ruby on Rails mailing list
62
+
63
+ Or, to contact the author, send mail to bitserf@gmail.com
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ require 'rake/contrib/rubyforgepublisher'
8
8
 
9
9
  PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
10
10
  PKG_NAME = 'actionservice'
11
- PKG_VERSION = '0.2.100' + PKG_BUILD
11
+ PKG_VERSION = '0.2.102' + PKG_BUILD
12
12
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
13
13
 
14
14
  desc "Default Task"
@@ -27,12 +27,13 @@ Rake::TestTask.new { |t|
27
27
  Rake::RDocTask.new { |rdoc|
28
28
  rdoc.rdoc_dir = 'doc'
29
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')
30
+ rdoc.options << '--line-numbers --inline-source --main README --accessor class_inheritable_option=RW'
31
+ rdoc.rdoc_files.include('README')
32
32
  rdoc.rdoc_files.include('lib/action_service.rb')
33
33
  rdoc.rdoc_files.include('lib/action_service/*.rb')
34
34
  rdoc.rdoc_files.include('lib/action_service/protocol/*.rb')
35
35
  rdoc.rdoc_files.include('lib/action_service/router/*.rb')
36
+ rdoc.rdoc_files.include('lib/action_service/support/*.rb')
36
37
  }
37
38
 
38
39
 
@@ -50,13 +51,14 @@ spec = Gem::Specification.new do |s|
50
51
  s.homepage = "http://rubyforge.org/projects/actionservice"
51
52
 
52
53
  s.add_dependency('actionpack', '>= 1.4.0')
54
+ s.add_dependency('activerecord', '>= 1.6.0')
53
55
 
54
56
  s.has_rdoc = true
55
57
  s.requirements << 'none'
56
58
  s.require_path = 'lib'
57
59
  s.autorequire = 'action_service'
58
60
 
59
- s.files = [ "Rakefile", "setup.rb", "README", "TODO", "HACKING", "CHANGELOG", "MIT-LICENSE" ]
61
+ s.files = [ "Rakefile", "setup.rb", "README", "TODO", "HACKING", "ChangeLog", "MIT-LICENSE" ]
60
62
  s.files = s.files + Dir.glob( "examples/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
61
63
  s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
62
64
  s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
@@ -96,6 +98,7 @@ task :lines do
96
98
  action_service
97
99
  action_service/protocol
98
100
  action_service/router
101
+ action_service/support
99
102
  }.each do |dir|
100
103
  Dir.foreach(File.join(prefix, dir)) { |file_name|
101
104
  next unless file_name =~ /.*rb$/
data/TODO CHANGED
@@ -1,30 +1,13 @@
1
- = Features Remaining
2
- - Support for ActiveRecord model classes as structure types as well, since
3
- we can reflect all the details to do proper mapping from model classes.
4
-
5
- = Ideas
6
- - <nextangle> Support a second dispatching mechanism, where incoming
7
- operation requests are mapped directly to a controller action.
8
-
9
- Advantages: No seperate API service class, the controller becomes the
10
- service class.
11
-
12
- Possible approaches:
13
- Create a new router that maps an 'api' action to do dispatching using
14
- itself as the target service.
15
-
16
- This dispatching would:
17
-
18
- * Unpack request parameters into @params
19
- * Execute the action
20
- * Use the return value of the action to send back to the client
21
-
22
- = Warts
23
- - Come up with a cleaner way for supporting XML-RPC introspection that doesn't
24
- involve throwing a SystemExportNotHandledError exception.
25
- - Come up with a cleaner approach for 'default_export' implementations.
26
- But NOT method_missing!
27
- - Create abstract SOAP test that provides helpers for doing SOAP method
28
- calls, get rid of the copy & paste SOAP crap in the SOAP protocol tests
1
+ = Tasks
2
+ - add better type mapping tests for XML-RPC
3
+ - add tests for ActiveRecord support (with mock objects?)
4
+
5
+ = Refactoring
6
+ - Find an alternative way to map interesting types for SOAP (like ActiveRecord
7
+ model classes) that doesn't require creation of a sanitized copy object with data
8
+ copied from the real one. Ideally this would let us get rid of
9
+ ActionService::Struct altogether and provide a block that would yield the
10
+ attributes and values. "Filters" ? Not sure how to integrate with SOAP though.
11
+
29
12
  - Don't have clean way to go from SOAP Class object to the xsd:NAME type
30
- string
13
+ string -- NaHi possibly looking at remedying this situation
@@ -2,7 +2,6 @@ require 'google_search_service'
2
2
 
3
3
  class SearchController < ApplicationController
4
4
  wsdl_service_name 'GoogleSearch'
5
+ service_dispatching_mode :delegated
5
6
  service :beta3, GoogleSearchService.new
6
-
7
- # self.action_service_debugging = true
8
7
  end
@@ -68,7 +68,10 @@ class GoogleSearchService < ActionService::Base
68
68
 
69
69
  # For Mono, we have to clone objects if they're referenced by more than one place, otherwise
70
70
  # the Ruby SOAP collapses them into one instance and uses references all over the
71
- # place, confusing Mono
71
+ # place, confusing Mono.
72
+ #
73
+ # This has recently been fixed:
74
+ # http://bugzilla.ximian.com/show_bug.cgi?id=72265
72
75
  result.directoryCategories = [
73
76
  category("Web Development", "UTF-8"),
74
77
  category("Programming", "US-ASCII"),
@@ -84,7 +87,7 @@ class GoogleSearchService < ActionService::Base
84
87
  cat
85
88
  end
86
89
 
87
- export :doGetCachedPage, :returns => [String], :expects => [String, String]
90
+ export :doGetCachedPage, :returns => [String], :expects => [{:key=>String}, {:url=>String}]
88
91
  export :doGetSpellingSuggestion, :returns => [String], :expects => [String, String]
89
92
  export :doGoogleSearch, :returns => [GoogleSearchResult], :expects => [String, String, Integer, Integer, TrueClass, String, TrueClass, String, String, String]
90
93
  end
@@ -5,63 +5,8 @@ module ActionService
5
5
  end
6
6
 
7
7
  class Base
8
- class_inheritable_option :export_name_mangling, true
8
+ # Whether to send back a detailed stack trace to the remote caller
9
+ # when an exception is thrown on the server
9
10
  class_inheritable_option :report_exceptions, true
10
- class_inheritable_option :logger
11
- class_inheritable_option :default_export
12
-
13
- class << self
14
- def export(name, options={})
15
- validate_options([:expects, :returns, :expects_and_returns], options.keys)
16
- if options[:expects_and_returns]
17
- expects = options[:expects_and_returns]
18
- returns = options[:expects_and_returns]
19
- else
20
- expects = options[:expects]
21
- returns = options[:returns]
22
- end
23
- name = name.to_sym
24
- public_name = public_export_name(name)
25
- info = { :expects => expects, :returns => returns }
26
- write_inheritable_hash("action_service_exports", name => info)
27
- write_inheritable_hash("action_service_public_exports", public_name => name)
28
- end
29
-
30
- def has_export?(name)
31
- exports.has_key?(name)
32
- end
33
-
34
- def has_public_export?(name)
35
- public_exports.has_key?(name)
36
- end
37
-
38
- def public_export_name(export_name)
39
- if export_name_mangling
40
- Inflector.camelize(export_name.to_s)
41
- else
42
- export_name.to_s
43
- end
44
- end
45
-
46
- def internal_export_name(public_name)
47
- public_exports[public_name]
48
- end
49
-
50
- def exports
51
- read_inheritable_attribute("action_service_exports") || {}
52
- end
53
-
54
- private
55
- def public_exports
56
- read_inheritable_attribute("action_service_public_exports") || {}
57
- end
58
-
59
- def validate_options(valid_option_keys, supplied_option_keys)
60
- unknown_option_keys = supplied_option_keys - valid_option_keys
61
- unless unknown_option_keys.empty?
62
- raise(ActionServiceError, "Unknown options: #{unknown_option_keys}")
63
- end
64
- end
65
- end
66
11
  end
67
12
  end
@@ -1,10 +1,14 @@
1
1
  module ActionService
2
2
  module Container
3
+ DirectDispatching = :direct
4
+ DelegatedDispatching = :delegated
5
+
3
6
  class ContainerError < ActionService::ActionServiceError
4
7
  end
5
8
 
6
9
  def self.append_features(base)
7
10
  super
11
+ base.class_inheritable_option(:service_dispatching_mode, DirectDispatching)
8
12
  base.extend(ClassMethods)
9
13
  base.send(:include, ActionService::Container::InstanceMethods)
10
14
  end
@@ -25,7 +29,7 @@ module ActionService
25
29
  end
26
30
 
27
31
  def add_service_definition_callback(&block)
28
- write_inheritable_array("action_service_definition_callbacks", [block])
32
+ write_inheritable_array("service_definition_callbacks", [block])
29
33
  end
30
34
 
31
35
  def has_service?(name)
@@ -37,9 +41,9 @@ module ActionService
37
41
  end
38
42
 
39
43
  private
40
- def call_service_definition_callbacks(container_klass, service_name, service_info)
41
- (read_inheritable_attribute("action_service_definition_callbacks") || []).each do |block|
42
- block.call(container_klass, service_name, service_info)
44
+ def call_service_definition_callbacks(container_class, service_name, service_info)
45
+ (read_inheritable_attribute("service_definition_callbacks") || []).each do |block|
46
+ block.call(container_class, service_name, service_info)
43
47
  end
44
48
  end
45
49
  end
@@ -55,56 +59,104 @@ module ActionService
55
59
  end
56
60
 
57
61
  private
58
- def dispatch_service_invocation_request(protocol, info)
59
- service = service_object(info.service_name)
60
- service_klass = service.class
61
- method_name = service_klass.internal_export_name(info.public_method_name)
62
- opts = {}
63
- params = []
62
+ def dispatch_service_request(protocol_request)
63
+ case service_dispatching_mode
64
+ when DirectDispatching
65
+ dispatch_direct_service_request(protocol_request)
66
+ when DelegatedDispatching
67
+ dispatch_delegated_service_request(protocol_request)
68
+ else
69
+ raise(ContainerError, "unsupported dispatching mode '#{service_dispatching_mode}'")
70
+ end
71
+ end
72
+
73
+ def dispatch_direct_service_request(protocol_request)
74
+ public_method_name = protocol_request.public_method_name
75
+ method_name = self.class.internal_export_name(public_method_name)
76
+ export_info = self.class.exports[method_name]
77
+ protocol_request.type = Protocol::CheckedMessage
78
+ protocol_request.signature = export_info[:expects]
79
+ protocol_request.return_signature = export_info[:returns]
80
+ @invocation_params = protocol_request.unmarshal
81
+ if export_info[:expects]
82
+ expects = export_info[:expects]
83
+ @params ||= {}
84
+ (1..@invocation_params.size).each do |i|
85
+ i -= 1
86
+ if expects[i].is_a?(Hash)
87
+ @params[expects[i].keys.shift.to_s] = @invocation_params[i]
88
+ else
89
+ @params["param#{i}"] = @invocation_params[i]
90
+ end
91
+ end
92
+ end
93
+ result = send(method_name)
94
+ protocol_request.marshal(result)
95
+ end
96
+
97
+ def dispatch_delegated_service_request(protocol_request)
98
+ service_name = protocol_request.service_name
99
+ service = service_object(service_name)
100
+ service_class = service.class
101
+ public_method_name = protocol_request.public_method_name
102
+ method_name = service_class.internal_export_name(public_method_name)
103
+
104
+ invocation = ActionService::Invocation::InvocationRequest.new(
105
+ ActionService::Invocation::ConcreteInvocation,
106
+ public_method_name,
107
+ method_name)
108
+
64
109
  if method_name
65
- export_info = service_klass.exports[method_name]
66
- strict = true
110
+ protocol_request.type = Protocol::CheckedMessage
111
+ export_info = service_class.exports[method_name]
112
+ protocol_request.signature = export_info[:expects]
113
+ protocol_request.return_signature = export_info[:returns]
114
+ invocation.params = protocol_request.unmarshal
67
115
  else
116
+ protocol_request.type = Protocol::UncheckedMessage
117
+ invocation.type = ActionService::Invocation::VirtualInvocation
68
118
  system_exports = self.class.read_inheritable_attribute('default_system_exports') || {}
69
- method_name = system_exports[protocol.class]
70
- if method_name
71
- opts[:system_call] = [info.public_method_name, system_exports[protocol.class]]
72
- params.unshift service_klass
119
+ protocol = protocol_request.protocol
120
+ block = system_exports[protocol.class]
121
+ if block
122
+ invocation.block = block
123
+ invocation.block_params << service_class
73
124
  else
74
- method_name = service_klass.default_export
75
- method_name = method_name.to_sym if method_name
76
- unless method_name
77
- raise(ContainerError, "no such method /#{info.service_name}##{info.public_method_name}()")
125
+ method_name = service_class.default_export
126
+ if method_name && service.respond_to?(method_name)
127
+ invocation.params = protocol_request.unmarshal
128
+ invocation.method_name = method_name.to_sym
129
+ else
130
+ raise(ContainerError, "no such method /#{service_name}##{public_method_name}")
78
131
  end
79
132
  end
80
- export_info = {}
81
- strict = false
82
133
  end
83
- opts[:require_exported] = false unless strict
84
- params = params + protocol.unmarshal_request(info, export_info, strict)
134
+
85
135
  canceled_reason = nil
86
136
  canceled_block = lambda{|r| canceled_reason = r}
87
137
  perform_invoke = lambda do
88
- service.perform_invocation(method_name, params, opts, &canceled_block)
138
+ service.perform_invocation(invocation, &canceled_block)
89
139
  end
90
- begin
140
+ try_default = true
141
+ result = nil
142
+ catch(:try_default_export) do
91
143
  result = perform_invoke.call
92
- rescue ActionService::Protocol::SystemExportNotHandledError => e
93
- params.shift
94
- method_name = service_klass.default_export
95
- opts.delete(:system_call)
144
+ try_default = false
145
+ end
146
+ if try_default
147
+ method_name = service_class.default_export
96
148
  if method_name
97
- method_name = method_name.to_sym
98
- export_info = {}
99
- strict = false
149
+ protocol_request.type = Protocol::UncheckedMessage
150
+ invocation.params = protocol_request.unmarshal
151
+ invocation.method_name = method_name.to_sym
152
+ invocation.type = ActionService::Invocation::UnexportedConcreteInvocation
100
153
  else
101
- raise(ContainerError, "no such method /#{info.service_name}##{info.public_method_name}()")
154
+ raise(ContainerError, "no such method /#{service_name}##{public_method_name}")
102
155
  end
103
156
  result = perform_invoke.call
104
157
  end
105
- protocol.marshal_response(info, export_info, result, strict)
158
+ protocol_request.marshal(result)
106
159
  end
107
-
108
160
  end
109
161
  end
110
162
  end
@@ -0,0 +1,140 @@
1
+ module ActionService
2
+ module Exporting
3
+ class ExportError < ActionService::ActionServiceError
4
+ end
5
+
6
+ def self.append_features(base)
7
+ super
8
+ # Whether to mangle method names into friendly camelized names
9
+ # when declaring them to remote callers
10
+ base.class_inheritable_option :export_name_mangling, true
11
+
12
+ # If present, the name of a method to call when the remote caller
13
+ # tried to call a nonexistent method. Semantically equivalent to
14
+ # +method_missing+.
15
+ base.class_inheritable_option :default_export
16
+
17
+ base.extend(ClassMethods)
18
+ end
19
+
20
+ module ClassMethods
21
+ # Declares the named method to be available for remote execution.
22
+ #
23
+ # Example:
24
+ #
25
+ # class CalculatorService < ActionService::Base
26
+ # def add(a, b)
27
+ # a + b
28
+ # end
29
+ #
30
+ # export :add, :expects => [Integer, Integer], :returns => [Integer]
31
+ # end
32
+ #
33
+ #
34
+ # You will need to provide type annotation options if the method will be
35
+ # receiving arguments, or returning values that will be used by remote
36
+ # callers.
37
+ #
38
+ # A type annotation is an Array, containing as elements one or more of:
39
+ #
40
+ # * A Class object for the desired type.
41
+ # * An Array containing a Class object. Declares that the argument at that
42
+ # position is to be an Array containing values of type Class.
43
+ # * A Hash containing the argument name as the key, and one of the above as
44
+ # value.
45
+ #
46
+ # Valid annotations:
47
+ # [<tt>:expects</tt>] The arguments that will be received by the method
48
+ # [<tt>:returns</tt>] The type of the method return value. May contain only one element.
49
+ # [<tt>:expects_and_returns</tt>] Shortcut for specifying <tt>:expects</tt> and <tt>:returns</tt> with the same signature.
50
+ #
51
+ # The public name of the method (that is, the name that must be used by
52
+ # remote callers) will be a _camelized_ version of +name+. Camelization is
53
+ # performed using Rails inflector camelization rules.
54
+ #
55
+ # Method name camelization can be turned off for a class by using the
56
+ # +export_name_mangling+ class option:
57
+ #
58
+ # class MyService < ActionService::Base
59
+ # export_name_mangling false
60
+ # end
61
+ def export(name, options={})
62
+ validate_options([:expects, :returns, :expects_and_returns], options.keys)
63
+ if options[:expects_and_returns]
64
+ expects = options[:expects_and_returns]
65
+ returns = options[:expects_and_returns]
66
+ else
67
+ expects = options[:expects]
68
+ returns = options[:returns]
69
+ end
70
+ if expects
71
+ expects.each do |klass|
72
+ klass = klass.values.shift if klass.is_a?(Hash)
73
+ klass = klass[0] if klass.is_a?(Array)
74
+ if klass.ancestors.include?(ActiveRecord::Base)
75
+ raise(ActionServiceError, "ActiveRecord model classes not allowed in :expects")
76
+ end
77
+ end
78
+ end
79
+ name = name.to_sym
80
+ public_name = public_export_name(name)
81
+ info = { :expects => expects, :returns => returns }
82
+ write_inheritable_hash("action_service_exports", name => info)
83
+ write_inheritable_hash("action_service_public_exports", public_name => name)
84
+ call_export_definition_callbacks(self, name, info)
85
+ end
86
+
87
+ # Whether the given name is exported by this service
88
+ def has_export?(name)
89
+ exports.has_key?(name)
90
+ end
91
+
92
+ # Whether the given public method name (mangled) is exported by
93
+ # this service
94
+ def has_public_export?(name)
95
+ public_exports.has_key?(name)
96
+ end
97
+
98
+ # The mangled public method name for the given method name
99
+ def public_export_name(export_name)
100
+ if export_name_mangling
101
+ Inflector.camelize(export_name.to_s)
102
+ else
103
+ export_name.to_s
104
+ end
105
+ end
106
+
107
+ # The internal method name for the given public method name
108
+ def internal_export_name(public_name)
109
+ public_exports[public_name]
110
+ end
111
+
112
+ # A Hash of method name to export information
113
+ def exports
114
+ read_inheritable_attribute("action_service_exports") || {}
115
+ end
116
+
117
+ def add_export_definition_callback(&block) # :nodoc:
118
+ write_inheritable_array("export_definition_callbacks", [block])
119
+ end
120
+
121
+ private
122
+ def call_export_definition_callbacks(service_class, export_name, export_info)
123
+ (read_inheritable_attribute("export_definition_callbacks") || []).each do |block|
124
+ block.call(service_class, export_name, export_info)
125
+ end
126
+ end
127
+
128
+ def public_exports
129
+ read_inheritable_attribute("action_service_public_exports") || {}
130
+ end
131
+
132
+ def validate_options(valid_option_keys, supplied_option_keys)
133
+ unknown_option_keys = supplied_option_keys - valid_option_keys
134
+ unless unknown_option_keys.empty?
135
+ raise(ActionServiceError, "Unknown options: #{unknown_option_keys}")
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
@@ -1,5 +1,9 @@
1
1
  module ActionService
2
2
  module Invocation
3
+ ConcreteInvocation = :concrete
4
+ VirtualInvocation = :virtual
5
+ UnexportedConcreteInvocation = :unexported_concrete
6
+
3
7
  class InvocationError < ActionService::ActionServiceError
4
8
  end
5
9
 
@@ -95,29 +99,29 @@ module ActionService
95
99
  end
96
100
  end
97
101
 
98
- def perform_invocation_with_interception(name, args=nil, options={}, &block)
99
- return if before_invocation(name, args, &block) == false
100
- result = perform_invocation_without_interception(name, args, options)
101
- after_invocation(name, args, result)
102
+ def perform_invocation_with_interception(invocation, &block)
103
+ return if before_invocation(invocation.method_name, invocation.params, &block) == false
104
+ result = perform_invocation_without_interception(invocation)
105
+ after_invocation(invocation.method_name, invocation.params, result)
102
106
  result
103
107
  end
104
108
 
105
- def perform_invocation(name, args=nil, options={})
106
- unless options[:require_exported] == false
107
- unless self.respond_to?(name) && self.class.has_export?(name)
108
- raise InvocationError, "no such exported method '#{name}'"
109
+ def perform_invocation(invocation)
110
+ if invocation.concrete?
111
+ unless self.respond_to?(invocation.method_name) && self.class.has_export?(invocation.method_name)
112
+ raise InvocationError, "no such exported method '#{invocation.method_name}'"
109
113
  end
110
114
  end
111
- args ||= []
112
- if options[:system_call]
113
- name, block = options[:system_call]
114
- if block.respond_to?('call')
115
- block.call(name, *args)
115
+ params = invocation.params
116
+ if invocation.concrete? || invocation.unexported_concrete?
117
+ self.send(invocation.method_name, *params)
118
+ else
119
+ if invocation.block
120
+ params = invocation.block_params + params
121
+ invocation.block.call(invocation.public_method_name, *params)
116
122
  else
117
- self.send(block, *args)
123
+ self.send(invocation.method_name, *params)
118
124
  end
119
- else
120
- self.send(name, *args)
121
125
  end
122
126
  end
123
127
 
@@ -177,7 +181,33 @@ module ActionService
177
181
  self.class.excluded_intercepted_methods[interceptor].include?(method_name)
178
182
  end
179
183
  end
184
+ end
185
+
186
+ class InvocationRequest
187
+ attr_accessor :type
188
+ attr :public_method_name
189
+ attr_accessor :method_name
190
+ attr_accessor :params
191
+ attr_accessor :block
192
+ attr :block_params
193
+
194
+ def initialize(type, public_method_name, method_name, params=nil)
195
+ @type = type
196
+ @public_method_name = public_method_name
197
+ @method_name = method_name
198
+ @params = params || []
199
+ @block = nil
200
+ @block_params = []
201
+ end
202
+
203
+ def concrete?
204
+ @type == ConcreteInvocation ? true : false
205
+ end
180
206
 
207
+ def unexported_concrete?
208
+ @type == UnexportedConcreteInvocation ? true : false
209
+ end
181
210
  end
211
+
182
212
  end
183
213
  end