Class: OroGen::Spec::Operation

Inherits:
Object
  • Object
show all
Defined in:
lib/orogen/spec/operation.rb

Overview

Representation of a RTT operation. Instances of this object are usually created through TaskContext#operation. The generated code will expect the class implementation (user-visible part) to define one method, to serve the call, with almost the same name that the method itself.

For instance, the following definition

operation('MyMethod')

will require the user-visible part to define

[return value] myMethod([arguments]);

(note that the first character of the method name has been set to lowercase to generate the C++ method name)

The argument list of the C++ method (the first one) can be defined using Callable#argument. Its return type by using #returns. The default method signature is no return type (i.e. void) and no arguments.

The name of the C++ method can be changed #method_name.

For instance,

operation('MyMethod').
  argument('x', 'double', 'the target X value').
  argument('y', 'double', 'the target Y value').
  method_name('move').
  returns('double')

will require the user-visible part to define

double move(double x, double y);

Constant Summary collapse

RTT_ARGUMENT_COUNT_LIMIT =
4

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(task, name) ⇒ Operation


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/orogen/spec/operation.rb', line 47

def initialize(task, name)
    name = name.to_s
    if name !~ /^\w+$/
        raise ArgumentError, "#{self.class.name.downcase} names need to be valid C++ identifiers, i.e. contain only alphanumeric characters and _ (got #{name})"
    end

    @task = task
    @name = name
    @return_type = [nil, 'void', ""]
    @arguments = []
    @in_caller_thread = false
    @doc = nil

    super()
end

Instance Attribute Details

#argumentsObject (readonly)

The set of arguments of this operation, as an array of [name, type, doc] elements. The type objects are Typelib::Type instances.

See #argument


102
103
104
# File 'lib/orogen/spec/operation.rb', line 102

def arguments
  @arguments
end

#in_caller_threadObject (readonly)

True if this operation runs its associated C++ method in caller thread (default is false)

See also #runs_in_caller_thread and #runs_in_callee_thread


43
44
45
# File 'lib/orogen/spec/operation.rb', line 43

def in_caller_thread
  @in_caller_thread
end

#nameObject (readonly)

The operation name


38
39
40
# File 'lib/orogen/spec/operation.rb', line 38

def name
  @name
end

#return_typeObject (readonly)

The return type of this operation, as a [type_object, qualified_cxx_type] pair.

See #returns


147
148
149
# File 'lib/orogen/spec/operation.rb', line 147

def return_type
  @return_type
end

#taskObject (readonly)

The TaskContext instance this operation is part of


36
37
38
# File 'lib/orogen/spec/operation.rb', line 36

def task
  @task
end

Instance Method Details

#arg(*args, &block) ⇒ Object

Shortcut for #arg


139
140
141
# File 'lib/orogen/spec/operation.rb', line 139

def arg(*args, &block)
    argument(*args, &block)
end

#argument(name, qualified_type, doc = "") ⇒ Object

Defines the next argument of this operation. name is the argument name and type is either the type name as a string, or a Typelib::Type object. In both cases, the required type must be defined in the task context, either because it is part of its own typekit or because it has been imported by a Project#load_typekit call.

Note that RTT does not support having more than 4 arguments for an operation, and trying that will therefore raise an error


128
129
130
131
132
133
134
135
136
# File 'lib/orogen/spec/operation.rb', line 128

def argument(name, qualified_type, doc = "")
    if arguments.size >= RTT_ARGUMENT_COUNT_LIMIT
        raise ArgumentError, "RTT does not support having more than #{RTT_ARGUMENT_COUNT_LIMIT} arguments for an operation"
    end

    type, qualified_type = find_interface_type(qualified_type)
    arguments << [name, type, doc, qualified_type]
    self
end

#each_interface_typeObject


63
64
65
66
67
68
69
70
71
# File 'lib/orogen/spec/operation.rb', line 63

def each_interface_type
    return enum_for(__method__) if !block_given?
    if ret = return_type.first
        yield(ret)
    end
    arguments.each do |_, t, _|
        yield(t)
    end
end

#find_interface_type(qualified_type) ⇒ Object

This version of find_interface_type returns both a Typelib::Type object and a normalized version for name. It does accept const and reference qualifiers in name.


107
108
109
110
111
112
113
114
115
116
# File 'lib/orogen/spec/operation.rb', line 107

def find_interface_type(qualified_type)
    if qualified_type.respond_to?(:name)
        qualified_type = qualified_type.name
    end
    type_name = OroGen.unqualified_cxx_type(qualified_type)
    typelib_type_name = ::Typelib::GCCXMLLoader.cxx_to_typelib(type_name)
    type      = task.project.find_interface_type(typelib_type_name)
    OroGen.validate_toplevel_type(type)
    return type, qualified_type.gsub(type_name, type.cxx_name)
end

#has_return_value?Boolean

Returns true if this operation's signature is not void


166
167
168
# File 'lib/orogen/spec/operation.rb', line 166

def has_return_value?
    !!@return_type.first
end

#pretty_print(pp) ⇒ Object


170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/orogen/spec/operation.rb', line 170

def pretty_print(pp)
    pp.text name
    pp.nest(2) do
        if self.doc
            pp.breakable
            pp.text self.doc
        end
        if !self.return_type[2].empty?
            pp.breakable
            pp.text "Returns: #{self.return_type[2]}"
        end
        arguments.map do |name, type, doc, qualified_type|
            pp.breakable
            pp.text "#{name}: #{doc}"
        end
    end
end

#returns(type, doc = "") ⇒ Object

Sets the return type for this operation. type can either be the type name or a Typelib::Type object. In both cases, the required type must be defined in the underlying project, either because it is part of its own typekit or because it has been imported by a Project#load_typekit call.


154
155
156
157
158
159
160
161
162
163
# File 'lib/orogen/spec/operation.rb', line 154

def returns(type, doc = "")
    @return_type =
        if type
            type, qualified_type = find_interface_type(type)
            [type, qualified_type, doc]
        else [nil, 'void', doc]
        end

    self
end

#runs_in_callee_threadObject

Declares that the C++ method associated with this operation should be executed in the caller thread

See also #runs_in_callee_thread and #in_caller_thread


86
87
88
89
# File 'lib/orogen/spec/operation.rb', line 86

def runs_in_callee_thread
    @in_caller_thread = false
    self
end

#runs_in_caller_threadObject

Declares that the C++ method associated with this operation should be executed in the caller thread (default is callee thread)

See also #runs_in_callee_thread and #in_caller_thread


77
78
79
80
# File 'lib/orogen/spec/operation.rb', line 77

def runs_in_caller_thread
    @in_caller_thread = true
    self
end

#to_hHash

Converts this model into a representation that can be fed to e.g. a JSON dump, that is a hash with pure ruby key / values.

The generated hash has the following keys:

name: the operation name
returns: the operation return type. It is not present if the
  operation does not return anything
    type: the return type as marshalled with
      Typelib::Type#to_h
    doc: the return type documentation

arguments: the list of arguments as an array of
    name: the argument name
    type: the argument type as marshalled with
      Typelib::Type#to_h
    doc: the argument documentation

208
209
210
211
212
213
214
215
216
217
# File 'lib/orogen/spec/operation.rb', line 208

def to_h
    result = Hash[name: name, doc: (doc || "")]
    if has_return_value?
        result[:returns] = Hash[type: self.return_type[0].to_h, doc: self.return_type[2]]
    end
    result[:arguments] = arguments.map do |name, type, doc, qualified_type|
        Hash[name: name, type: type.to_h, doc: doc]
    end
    result
end