krpc 0.1.0

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.
@@ -0,0 +1,12 @@
1
+ require 'krpc/doc'
2
+
3
+ module KRPC
4
+ module REPLTools
5
+ def proc_doc(service_name, procedure_name)
6
+ puts Doc.docstring_for_procedure(service_name, procedure_name)
7
+ end
8
+ end
9
+ end
10
+
11
+ include KRPC::REPLTools
12
+
@@ -0,0 +1,96 @@
1
+ require 'krpc/gen'
2
+ require 'krpc/attributes'
3
+ require 'krpc/doc'
4
+
5
+ module KRPC
6
+ module Services
7
+ class << self
8
+
9
+ def create_service(service_msg, client)
10
+ service_name = service_msg.name
11
+
12
+ # Create service class
13
+ service_class = Class.new(ServiceBase)
14
+ const_set(service_name, service_class)
15
+
16
+ # Create service' classes
17
+ service_msg.classes.map(&:name).each do |sc_name|
18
+ client.type_store.as_type("Class(#{service_name}.#{sc_name})")
19
+ end
20
+
21
+ # Create service' enums
22
+ service_msg.enumerations.each do |enum|
23
+ enum_type = client.type_store.as_type("Enum(#{service_name}.#{enum.name})")
24
+ enum_type.set_values(enum.values)
25
+ end
26
+
27
+ # Create service' procedures
28
+ service_msg.procedures.each do |proc|
29
+ if Attributes.is_a_class_method_or_property_accessor(proc.attributes)
30
+ class_name = Attributes.get_class_name(proc.attributes)
31
+ class_cls = client.type_store.as_type("Class(#{service_name}.#{class_name})").ruby_type
32
+ method_name = Attributes.get_class_method_or_property_name(proc.attributes)
33
+ if Attributes.is_a_class_property_accessor(proc.attributes) # service' class property
34
+ if Attributes.is_a_class_property_getter(proc.attributes)
35
+ Gen.add_rpc_method(class_cls, method_name, service_name, proc, client, :prepend_self_to_args)
36
+ else
37
+ Gen.add_rpc_method(class_cls, method_name + '=', service_name, proc, client, :prepend_self_to_args)
38
+ end
39
+ elsif Attributes.is_a_class_method(proc.attributes) # service' class method
40
+ Gen.add_rpc_method(class_cls, method_name, service_name, proc, client, :prepend_self_to_args)
41
+ else # service' static class method
42
+ Gen.add_rpc_method(class_cls, method_name, service_name, proc, client, :static)
43
+ end
44
+ elsif Attributes.is_a_property_accessor(proc.attributes) # service' property
45
+ property_name = Attributes.get_property_name(proc.attributes)
46
+ if Attributes.is_a_property_getter(proc.attributes)
47
+ Gen.add_rpc_method(service_class, property_name, service_name, proc, client)
48
+ elsif Attributes.is_a_property_setter(proc.attributes)
49
+ Gen.add_rpc_method(service_class, property_name + '=', service_name, proc, client)
50
+ end
51
+ else # plain procedure = method available to service class and its instance
52
+ Gen.add_rpc_method(service_class, proc.name, service_name, proc, client, :static)
53
+ end
54
+ end
55
+
56
+ # Add methods available to class and instance in service class & service' classes
57
+ service_class.add_methods_available_to_class_and_instance
58
+ mod = Gen.service_gen_module(service_name)
59
+ service_classes = mod.constants.map{|c| mod.const_get(c)}.select {|c| c.is_a? Class}
60
+ service_classes.each(&:add_methods_available_to_class_and_instance)
61
+
62
+ # Return service class instance
63
+ service_class.new(client)
64
+ end
65
+
66
+ end
67
+
68
+ class ServiceBase
69
+ extend Gen::AvailableToClassAndInstanceMethodsHandler
70
+ include Doc::SuffixMethods
71
+
72
+ attr_reader :client
73
+
74
+ def initialize(client)
75
+ @client = client
76
+ end
77
+ end
78
+
79
+ class KRPC < ServiceBase
80
+ include Gen::RPCMethodGenerator
81
+
82
+ def initialize(client)
83
+ super(client)
84
+ unless respond_to? :get_status
85
+ include_rpc_method("get_status", "KRPC", "GetStatus", return_type: "KRPC.Status")
86
+ include_rpc_method("get_services", "KRPC", "GetServices", return_type: "KRPC.Services")
87
+ # TODO: implement me:
88
+ # include_rpc_method("add_stream", "KRPC", "AddStream", ...)
89
+ # include_rpc_method("remove_stream", "KRPC", "RemoveStream", ...)
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+
@@ -0,0 +1,237 @@
1
+ require 'krpc/gen'
2
+ require 'krpc/attributes'
3
+ require 'krpc/protobuf_utils'
4
+ require 'krpc/error'
5
+ require 'krpc/core_extensions'
6
+ require 'set'
7
+
8
+ module KRPC
9
+ module Types
10
+ PROTOBUF_VALUE_TYPES = ["double", "float", "int32", "int64", "uint32", "uint64", "bool", "string", "bytes"]
11
+ RUBY_VALUE_TYPES = [Float, Integer, Boolean, String]
12
+ PROTOBUF_TO_RUBY_VALUE_TYPE = {
13
+ "double" => Float,
14
+ "float" => Float,
15
+ "int32" => Integer,
16
+ "int64" => Integer,
17
+ "uint32" => Integer,
18
+ "uint64" => Integer,
19
+ "bool" => Boolean,
20
+ "string" => String,
21
+ "bytes" => String
22
+ }
23
+ PROTOBUF_TO_MESSAGE_TYPE = ProtobufUtils.create_PB_to_PB_message_class_hash("KRPC")
24
+
25
+ class TypeStore
26
+
27
+ def initialize
28
+ @cache = {}
29
+ end
30
+
31
+ def as_type(type_string)
32
+ return @cache[type_string] if @cache.include? type_string
33
+
34
+ type =
35
+ if PROTOBUF_VALUE_TYPES.include? type_string then ValueType.new(type_string)
36
+ elsif type_string.start_with? "Class(" || type_string == "Class" then ClassType.new(type_string)
37
+ elsif type_string.start_with? "Enum(" || type_string == "Enum" then EnumType.new(type_string)
38
+ elsif type_string.start_with? "List(" || type_string == "List" then ListType.new(type_string, self)
39
+ elsif type_string.start_with? "Dictionary(" || type_string == "Dictionary" then DictionaryType.new(type_string, self)
40
+ elsif type_string.start_with? "Set(" || type_string == "Set" then SetType.new(type_string, self)
41
+ elsif type_string.start_with? "Tuple(" || type_string == "Tuple" then TupleType.new(type_string, self)
42
+ else # A message type (eg. type_string = "KRPC.List" or "KRPC.Services")
43
+ raise(ValueError, "\"#{type_string}\" is not a valid type string") unless /^[A-Za-z0-9_\.]+$/ =~ type_string
44
+ if PROTOBUF_TO_MESSAGE_TYPE.has_key? type_string
45
+ MessageType.new(type_string)
46
+ else
47
+ raise(ValueError, "\"#{type_string}\" is not a valid type string")
48
+ end
49
+ end
50
+
51
+ @cache[type_string] = type
52
+ type
53
+ end
54
+
55
+ def get_parameter_type(pos, type, attrs)
56
+ type_attrs = Attributes.get_parameter_type_attrs(pos, attrs)
57
+ type_attrs.each do |ta|
58
+ begin
59
+ return as_type(ta)
60
+ rescue ValueError
61
+ end
62
+ end
63
+ as_type(type)
64
+ end
65
+
66
+ def get_return_type(type, attrs)
67
+ type_attrs = Attributes.get_return_type_attrs(attrs)
68
+ type_attrs.each do |ta|
69
+ begin
70
+ return as_type(ta)
71
+ rescue ValueError
72
+ end
73
+ end
74
+ as_type(type)
75
+ end
76
+
77
+ def coerce_to(value, type)
78
+ return value if type.is_a?(EnumType) && value.class == Symbol # Enum handling
79
+ return value if value.is_a?(type.ruby_type)
80
+ # A NilClass can be coerced to a ClassType
81
+ return nil if type.is_a?(ClassType) && value == nil
82
+ # Coerce identical class types from different client connections
83
+ if type.is_a?(ClassType) && value.is_a?(Gen::ClassBase) &&
84
+ type.ruby_type.service_name == value.class.service_name &&
85
+ type.ruby_type.name == value.class.name
86
+ return type.ruby_type.new(value.remote_oid)
87
+ end
88
+ # -- Collection types --
89
+ begin
90
+ # coerce "list" to array
91
+ if type.is_a?(ListType) && value.respond_to?(:map) && value.respond_to?(:to_a)
92
+ return type.ruby_type.new(value.map{|x| coerce_to(x, type.value_type) }.to_a)
93
+ end
94
+ # coerce "tuple" to array + check elements count
95
+ if type.is_a?(TupleType) && value.respond_to?(:map) && value.respond_to?(:to_a) && value.respond_to?(:size)
96
+ raise ValueError if value.size != type.value_types.size
97
+ return type.ruby_type.new(value.map.with_index{|x,i| coerce_to(x, type.value_types[i]) }.to_a)
98
+ end
99
+ rescue ValueError
100
+ raise(ValueError, "Failed to coerce value #{value.to_s} of type #{value.class} to type #{type}")
101
+ end
102
+ # Numeric types
103
+ if type.ruby_type == Float && value.respond_to?(:to_f)
104
+ return value.to_f
105
+ elsif type.ruby_type == Integer && value.respond_to?(:to_i)
106
+ return value.to_i
107
+ end
108
+ raise(ValueError, "Failed to coerce value #{value.to_s} of type #{value.class} to type #{type}")
109
+ end
110
+
111
+ end
112
+
113
+
114
+ class TypeBase
115
+ attr_reader :protobuf_type, :ruby_type
116
+ def initialize(protobuf_type, ruby_type)
117
+ @protobuf_type = protobuf_type
118
+ @ruby_type = ruby_type
119
+ end
120
+
121
+ protected
122
+
123
+ def parse_type_string(type)
124
+ raise ValueError.new if type == nil
125
+ result = ""
126
+ level = 0
127
+ type.each_char do |x|
128
+ break if level == 0 && x == ','
129
+ level += 1 if x == '('
130
+ level -= 1 if x == ')'
131
+ result += x
132
+ end
133
+ raise ValueError.new if level != 0
134
+ return [result, nil] if result == type
135
+ raise ValueError.new if type[result.length] != ','
136
+ [result, type[(result.length+1)..-1]]
137
+ end
138
+ end
139
+
140
+ class ValueType < TypeBase
141
+ def initialize(type_string)
142
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a value type") unless PROTOBUF_TO_RUBY_VALUE_TYPE.has_key? type_string
143
+ super(type_string, PROTOBUF_TO_RUBY_VALUE_TYPE[type_string])
144
+ end
145
+ end
146
+
147
+ class MessageType < TypeBase
148
+ def initialize(type_string)
149
+ if PROTOBUF_TO_MESSAGE_TYPE.has_key? type_string
150
+ super(type_string, PROTOBUF_TO_MESSAGE_TYPE[type_string])
151
+ else
152
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a message type")
153
+ end
154
+ end
155
+ end
156
+
157
+ class ClassType < TypeBase
158
+ attr_reader :service_name, :class_name
159
+ def initialize(type_string)
160
+ m = /Class\(([^\.]+)\.([^\.]+)\)/.match type_string
161
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a class type") unless m
162
+ @service_name, @class_name = m[1..2]
163
+ super(type_string, Gen.generate_class(service_name, class_name))
164
+ end
165
+ end
166
+
167
+ class EnumType < TypeBase
168
+ attr_reader :service_name, :enum_name
169
+ def initialize(type_string)
170
+ m = /Enum\(([^\.]+)\.([^\.]+)\)/.match type_string
171
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a enumeration type") unless m
172
+ @service_name, @enum_name = m[1..2]
173
+ # Sets ruby_type to nil, set_values must be called to set the ruby_type
174
+ super(type_string, nil)
175
+ end
176
+
177
+ def set_values(values)
178
+ @ruby_type = Gen.generate_enum(service_name, enum_name, values)
179
+ end
180
+ end
181
+
182
+ class ListType < TypeBase
183
+ attr_reader :value_type
184
+ def initialize(type_string, type_store)
185
+ m = /^List\((.+)\)$/.match type_string
186
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a list type") unless m
187
+ @value_type = type_store.as_type(m[1])
188
+ super(type_string, Array)
189
+ end
190
+ end
191
+
192
+ class DictionaryType < TypeBase
193
+ attr_reader :key_type, :value_type
194
+ def initialize(type_string, type_store)
195
+ m = /^Dictionary\((.+)\)$/.match type_string
196
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a dictionary type") unless m
197
+
198
+ key_string, type = parse_type_string(m[1])
199
+ value_string, type = parse_type_string(type)
200
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a dictionary type") if type != nil
201
+ @key_type = type_store.as_type(key_string)
202
+ @value_type = type_store.as_type(value_string)
203
+
204
+ super(type_string, Hash)
205
+ end
206
+ end
207
+
208
+ class SetType < TypeBase
209
+ attr_reader :value_type
210
+ def initialize(type_string, type_store)
211
+ m = /^Set\((.+)\)$/.match type_string
212
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a set type") unless m
213
+ @value_type = type_store.as_type(m[1])
214
+ super(type_string, Set)
215
+ end
216
+ end
217
+
218
+ class TupleType < TypeBase
219
+ attr_reader :value_types
220
+ def initialize(type_string, type_store)
221
+ m = /^Tuple\((.+)\)$/.match type_string
222
+ raise(ValueError, "\"#{type_string}\" is not a valid type string for a tuple type") unless m
223
+
224
+ @value_types = []
225
+ type = m[1]
226
+ while type != nil
227
+ value_type, type = parse_type_string(type)
228
+ @value_types << type_store.as_type(value_type)
229
+ end
230
+
231
+ super(type_string, Array)
232
+ end
233
+ end
234
+
235
+ end
236
+ end
237
+
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: krpc
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Tomasz Więch
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-09-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ruby_protobuf
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.4'
27
+ - !ruby/object:Gem::Dependency
28
+ name: colorize
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.7'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ description:
56
+ email:
57
+ - tewu.dev@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - krpc.gemspec
65
+ - lib/krpc.rb
66
+ - lib/krpc/KRPC.pb.rb
67
+ - lib/krpc/attributes.rb
68
+ - lib/krpc/client.rb
69
+ - lib/krpc/connection.rb
70
+ - lib/krpc/core_extensions.rb
71
+ - lib/krpc/decoder.rb
72
+ - lib/krpc/doc.rb
73
+ - lib/krpc/encoder.rb
74
+ - lib/krpc/error.rb
75
+ - lib/krpc/gen.rb
76
+ - lib/krpc/protobuf_utils.rb
77
+ - lib/krpc/repl_tools.rb
78
+ - lib/krpc/service.rb
79
+ - lib/krpc/types.rb
80
+ homepage: https://github.com/TeWu/krpc-rb
81
+ licenses:
82
+ - GPL-3.0
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.4.8
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: Client library for kRPC
104
+ test_files: []
105
+ has_rdoc: