krpc 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: