rubimc 0.2.1
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.
- checksums.yaml +7 -0
- data/LICENSE.md +21 -0
- data/README.md +176 -0
- data/bin/rubimc +190 -0
- data/lib/rubimc/control_structures.rb +58 -0
- data/lib/rubimc/controllers.rb +46 -0
- data/lib/rubimc/init_var.rb +99 -0
- data/lib/rubimc/io_ports.rb +66 -0
- data/lib/rubimc/mcu/avr/attiny13.rb +176 -0
- data/lib/rubimc/mcu/avr/avr_controller.rb +16 -0
- data/lib/rubimc/preprocessor.rb +354 -0
- data/lib/rubimc/printer.rb +143 -0
- data/lib/rubimc/ruby_classes.rb +54 -0
- data/lib/rubimc.rb +234 -0
- data/lib/version.rb +3 -0
- metadata +60 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
def print_comment(comment)
|
|
2
|
+
comment.lines.each do |line|
|
|
3
|
+
RubimCode.pout "// #{line}"
|
|
4
|
+
end
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def printf(str, *args)
|
|
8
|
+
if args.empty?
|
|
9
|
+
RubimCode.pout("printf(#{str.dump});")
|
|
10
|
+
else
|
|
11
|
+
args_str = args.join(', ')
|
|
12
|
+
RubimCode.pout("printf(#{str.dump}, #{args_str});")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RubimCode
|
|
18
|
+
class << self
|
|
19
|
+
|
|
20
|
+
attr_accessor :level
|
|
21
|
+
def level
|
|
22
|
+
@level = 0 if @level.nil?
|
|
23
|
+
@level
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def perror(error_message)
|
|
27
|
+
if error_message.nil? or error_message.to_s.nil?
|
|
28
|
+
raise ArgumentError, "error message is not string"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
error_message += "\n"
|
|
32
|
+
code_ptr = caller_locations(2)
|
|
33
|
+
code_ptr.each do |place|
|
|
34
|
+
place = place.to_s
|
|
35
|
+
place.gsub!(/^release\/pre_/, '')
|
|
36
|
+
error_message += "\tfrom #{place}\n"
|
|
37
|
+
end
|
|
38
|
+
puts "#ERROR: #{error_message}"
|
|
39
|
+
exit 1
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def pout(str = "")
|
|
43
|
+
return if RubimCode::Printer.sandbox == true # don`t print output in sandbox
|
|
44
|
+
|
|
45
|
+
if str.nil? or str.to_s.nil?
|
|
46
|
+
raise ArgumentError, "str is nil"
|
|
47
|
+
else
|
|
48
|
+
@level = 0 if @level.nil?
|
|
49
|
+
res_str = " "*4*@level + str.to_s
|
|
50
|
+
if (($pout_destination == :default) or ($pout_destination.nil?))
|
|
51
|
+
puts res_str
|
|
52
|
+
unless defined? TEST_MODE
|
|
53
|
+
File.open("#{ARGV[0]}", 'a+') {|file| file.puts(res_str) }
|
|
54
|
+
end
|
|
55
|
+
else
|
|
56
|
+
$pout_destination.concat(res_str).concat("\n")
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# ToDo: remove to RubimCode::Printer
|
|
62
|
+
$pout_destination = :default
|
|
63
|
+
def pout_destination=(dest)
|
|
64
|
+
if dest.nil?
|
|
65
|
+
perror "Wrong parameter for method #{__method__}. Set destination string"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
if dest.class.name == "String" or dest == :default # dest.is_a? not work...WTF
|
|
69
|
+
$pout_destination = dest
|
|
70
|
+
else
|
|
71
|
+
perror "Wrong parameter for method #{__method__}. Only string variable or ':default' value is permit as a parameters"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def clear_c(str)
|
|
76
|
+
pout "// generate with clear_c function"
|
|
77
|
+
pout str
|
|
78
|
+
pout "// end clear_c function"
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
end # class << self
|
|
83
|
+
end # RubimCode class
|
|
84
|
+
|
|
85
|
+
class RubimCode::Printer
|
|
86
|
+
class << self
|
|
87
|
+
attr_accessor :sandbox
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def self.code_type
|
|
91
|
+
if not Controllers.all.empty?
|
|
92
|
+
"avr-gcc"
|
|
93
|
+
elsif Controllers.all.empty? and eval("self.private_methods.include? :main")
|
|
94
|
+
"gcc"
|
|
95
|
+
else
|
|
96
|
+
RubimCode.perror "Can not to define type of code"
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.mcu_type
|
|
101
|
+
code_type == "avr-gcc" ? Controllers.all.first::MCU_NAME : "undefined"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def self.print_main_loop
|
|
105
|
+
RubimCode.pout
|
|
106
|
+
RubimCode.pout "// === Main Infinite Loop === //"
|
|
107
|
+
RubimCode.pout "while (true) {"
|
|
108
|
+
RubimCode.level += 1
|
|
109
|
+
yield # print body of main loop
|
|
110
|
+
RubimCode.level -= 1
|
|
111
|
+
RubimCode.pout"} // end main loop"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def self.generate_cc
|
|
115
|
+
if Controllers.all.count > 1
|
|
116
|
+
RubimCode.perror "In current version in one file you can define only one Controller Class"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
if self.code_type == "avr-gcc" # if compile program for MCU
|
|
120
|
+
Controllers.all.each do |controllerClass|
|
|
121
|
+
controllerClass.print_layout(:before_main)
|
|
122
|
+
controller = controllerClass.new # print initialize section
|
|
123
|
+
print_main_loop {controller.main_loop} # print body of main loop
|
|
124
|
+
controllerClass.print_layout(:after_main)
|
|
125
|
+
RubimCode::Interrupts.print
|
|
126
|
+
end # each Controllers.all
|
|
127
|
+
|
|
128
|
+
elsif self.code_type == "gcc" # if compile clear-C program
|
|
129
|
+
if Controllers.all.empty? and eval("self.private_methods.include? :main")
|
|
130
|
+
Controllers.print_cc_layout(:before_main)
|
|
131
|
+
eval("main(RubimCode::CC_ARGS.new)") # execute method :main (CC_ARGS - helper for C agruments argc/argv)
|
|
132
|
+
Controllers.print_cc_layout(:after_main)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
END { # execute when user`s program is end
|
|
138
|
+
exit 0 if defined? TEST_MODE
|
|
139
|
+
exit 0 if sandbox == true
|
|
140
|
+
self.generate_cc
|
|
141
|
+
exit 0
|
|
142
|
+
}
|
|
143
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class Object
|
|
2
|
+
def not_nil?
|
|
3
|
+
!self.nil?
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def has_parent?(name)
|
|
7
|
+
return false unless self.respond_to? :ancestors
|
|
8
|
+
self!=name and self.ancestors.include?(name)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def to_rubim
|
|
12
|
+
type = case self.class.name
|
|
13
|
+
when "Fixnum" then 'int'
|
|
14
|
+
when "Float" then 'float'
|
|
15
|
+
when "String" then 'string'
|
|
16
|
+
else nil
|
|
17
|
+
end
|
|
18
|
+
if type.nil? or self.to_s.nil?
|
|
19
|
+
perror "Неизвестный тип переменной"
|
|
20
|
+
end
|
|
21
|
+
UserVariable.new(self.to_s, type)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def in?(array)
|
|
25
|
+
array.each {|el| return true if el == self}
|
|
26
|
+
return false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class Class
|
|
32
|
+
# get list of all childs inhereted from self class
|
|
33
|
+
def descendants
|
|
34
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
|
35
|
+
end # see alternative realization: http://apidock.com/rails/Class/descendants
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
class Hash
|
|
39
|
+
def permit_and_default! (**args)
|
|
40
|
+
self.keys.each do |param|
|
|
41
|
+
if not args.keys.include? param
|
|
42
|
+
mname = caller_locations(1)[2].label
|
|
43
|
+
perror "Method '#{mname}' have no param: #{param}}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
args.keys.each do |param|
|
|
48
|
+
self[param] = args[param] if self[param].nil?
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
data/lib/rubimc.rb
ADDED
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
#####################################################################
|
|
2
|
+
# RubimCode CORE #
|
|
3
|
+
# #
|
|
4
|
+
# Author: Evgeny Danilov #
|
|
5
|
+
# Created at 2016 March-14 #
|
|
6
|
+
#####################################################################
|
|
7
|
+
class RubimCode; end
|
|
8
|
+
|
|
9
|
+
require "version"
|
|
10
|
+
require "rubimc/ruby_classes"
|
|
11
|
+
|
|
12
|
+
require "rubimc/io_ports"
|
|
13
|
+
require "rubimc/controllers"
|
|
14
|
+
require "rubimc/mcu/avr/avr_controller"
|
|
15
|
+
|
|
16
|
+
require "rubimc/printer"
|
|
17
|
+
require "rubimc/init_var"
|
|
18
|
+
require "rubimc/control_structures"
|
|
19
|
+
|
|
20
|
+
class RubimCode
|
|
21
|
+
|
|
22
|
+
class UserVariable
|
|
23
|
+
attr_accessor :name, :type
|
|
24
|
+
# attr_accessor :level # ToDo: для указания области видимости
|
|
25
|
+
def initialize(name, type = "undefined")
|
|
26
|
+
@name, @type = name.to_s, type.to_s
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_s
|
|
30
|
+
"(" + self.name + ")"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_i
|
|
34
|
+
@name.to_i
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_rubim
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def c_assign=(val)
|
|
42
|
+
RubimCode.pout "#{@name} = #{val};"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def common_operator(val, operator_sym)
|
|
46
|
+
if not val.class.respond_to? :to_s
|
|
47
|
+
RubimCode.perror "Conversion of variable #{val} is impossible. Method 'to_s' not found"
|
|
48
|
+
else
|
|
49
|
+
UserVariable.new(self.name + operator_sym.to_s + val.to_s)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Arithmetic Operators:
|
|
54
|
+
def +(val); common_operator(val, __method__); end
|
|
55
|
+
def -(val); common_operator(val, __method__); end
|
|
56
|
+
def *(val); common_operator(val, __method__); end
|
|
57
|
+
def /(val); common_operator(val, __method__); end
|
|
58
|
+
def %(val); common_operator(val, __method__); end
|
|
59
|
+
def **(val);common_operator(val, __method__); end
|
|
60
|
+
|
|
61
|
+
# Operators +=, -=, e.t.
|
|
62
|
+
# ToDo: (can not override; use preprocessor)
|
|
63
|
+
|
|
64
|
+
# Unary Operators:
|
|
65
|
+
def -@; UserVariable.new("(-" + self.name + ")"); end
|
|
66
|
+
def +@; UserVariable.new("(+" + self.name + ")"); end
|
|
67
|
+
def !@; UserVariable.new("(+" + self.name + ")"); end
|
|
68
|
+
def ~@; UserVariable.new("(+" + self.name + ")"); end
|
|
69
|
+
|
|
70
|
+
# Comparison Operators:
|
|
71
|
+
def ==(val); common_operator(val, __method__); end
|
|
72
|
+
def !=(val); common_operator(val, __method__); end
|
|
73
|
+
def <(val); common_operator(val, __method__); end
|
|
74
|
+
def >(val); common_operator(val, __method__); end
|
|
75
|
+
def <=(val); common_operator(val, __method__); end
|
|
76
|
+
def >=(val); common_operator(val, __method__); end
|
|
77
|
+
|
|
78
|
+
# Binary Operators:
|
|
79
|
+
def &(val); common_operator(val, __method__); end
|
|
80
|
+
def |(val); common_operator(val, __method__); end
|
|
81
|
+
def ^(val); common_operator(val, __method__); end
|
|
82
|
+
def <<(val); common_operator(val, __method__); end
|
|
83
|
+
def >>(val); common_operator(val, __method__); end
|
|
84
|
+
|
|
85
|
+
# Logical Operators: (and, or, not, &&, ||)
|
|
86
|
+
# can not override, use preprocessor
|
|
87
|
+
|
|
88
|
+
# Ternary Operators: (? :)
|
|
89
|
+
# ToDo...
|
|
90
|
+
|
|
91
|
+
# Ruby Parallel Assignment:
|
|
92
|
+
# a, b, c = 10, 20, 30 # ToDo
|
|
93
|
+
|
|
94
|
+
# ToDo: операторы, которым нет аналогов в Си
|
|
95
|
+
# def <=>(val); ??? end
|
|
96
|
+
# def ===(val); ??? end
|
|
97
|
+
# def =~(val); ??? end
|
|
98
|
+
# def !~(val); ??? end
|
|
99
|
+
|
|
100
|
+
# Range-operators ".." and "..."
|
|
101
|
+
# ToDo: is it need? or use Enumerator?
|
|
102
|
+
|
|
103
|
+
def times
|
|
104
|
+
n = LoopCounter.new
|
|
105
|
+
RubimCode.pout ("for (int #{n}=0; #{n}<#{self}; #{n}++) {")
|
|
106
|
+
RubimCode.level += 1
|
|
107
|
+
yield(n)
|
|
108
|
+
RubimCode.pout ("}")
|
|
109
|
+
RubimCode.level -= 1
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# ToDo: add mixins Enumerable and Comparable
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# ToDo: в Ruby присваивание значений индексной переменной
|
|
116
|
+
# не должно влиять на выполнение цикла
|
|
117
|
+
# например следующий цикл будет выполнен ровно 10 раз
|
|
118
|
+
# for var in 1..10; var = var+2; end
|
|
119
|
+
class LoopCounter < UserVariable
|
|
120
|
+
def initialize
|
|
121
|
+
name = "i" + RubimCode.level.to_s
|
|
122
|
+
# ToDo - вместо "i" - __rubim__i
|
|
123
|
+
super(name)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def to_s
|
|
127
|
+
self.name
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class UserArray < Array
|
|
132
|
+
attr_accessor :name, :type
|
|
133
|
+
|
|
134
|
+
def []=(index, val)
|
|
135
|
+
RubimCode.pout "#{@name}[#{index.to_i}] = #{val.to_s};"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def [](index)
|
|
139
|
+
super index.to_i
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def each
|
|
143
|
+
n = LoopCounter.new
|
|
144
|
+
RubimCode.pout "for (int #{n}=0; #{n}<#{self.size}; #{n}++) {"
|
|
145
|
+
RubimCode.level +=1
|
|
146
|
+
joy_name = self.name + "[#{n}]"
|
|
147
|
+
yield(self[0].class.new("#{joy_name}"))
|
|
148
|
+
RubimCode.level -=1
|
|
149
|
+
RubimCode.pout "}"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
# Наследник всех пользовательских классов
|
|
154
|
+
class UserClass < UserVariable
|
|
155
|
+
|
|
156
|
+
# список всех пользовательских "свойств" класса
|
|
157
|
+
@@var_array = {}
|
|
158
|
+
def self.add_var_array(user_class_name, value)
|
|
159
|
+
@@var_array[user_class_name.to_sym] ||= []
|
|
160
|
+
@@var_array[user_class_name.to_sym] << value
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# генерация класса (typedef struct + методы)
|
|
164
|
+
def self.generate_struct
|
|
165
|
+
RubimCode.pout "typedef struct {"
|
|
166
|
+
RubimCode.level +=1
|
|
167
|
+
@@var_array[self.to_s.to_sym].each do |var|
|
|
168
|
+
RubimCode.pout "#{var.type} #{var.name};"
|
|
169
|
+
end
|
|
170
|
+
RubimCode.pout "} #{self.to_s};"
|
|
171
|
+
RubimCode.level -=1
|
|
172
|
+
|
|
173
|
+
public_instance_methods(false).each do |method_name|
|
|
174
|
+
tmp_str = ""
|
|
175
|
+
pout_destination = tmp_str
|
|
176
|
+
return_var = self.new("(*params)").send(method_name).to_rubim
|
|
177
|
+
pout_destination = :default
|
|
178
|
+
return_var.type = "void" if return_var.type.nil? # if type is not set
|
|
179
|
+
|
|
180
|
+
RubimCode.pout "#{return_var.type} #{method_name.to_s} (#{self.to_s} *params) {"
|
|
181
|
+
RubimCode.level += 1
|
|
182
|
+
self.new("(*params)").send(method_name)
|
|
183
|
+
RubimCode.pout "return #{return_var};"
|
|
184
|
+
RubimCode.pout "}"
|
|
185
|
+
RubimCode.level -= 1
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
def self.redefine_users_methods
|
|
190
|
+
public_instance_methods(false).each do |method_name|
|
|
191
|
+
define_method(method_name) do
|
|
192
|
+
"#{__method__}(&#{self.name})"
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
# Список аппаратных прерываний (содержит Си-код в текстовом виде)
|
|
200
|
+
class Interrupts
|
|
201
|
+
@@interrupt_array = []
|
|
202
|
+
|
|
203
|
+
def self.array
|
|
204
|
+
@@interrupt_array
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def self.add(val)
|
|
208
|
+
if val.class.name == "String"
|
|
209
|
+
@@interrupt_array << val
|
|
210
|
+
else
|
|
211
|
+
RubimCode.perror "wrong params in method #{__method__}"
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def self.print
|
|
216
|
+
@@interrupt_array.each do |interrupt_code|
|
|
217
|
+
RubimCode.pout interrupt_code
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
class CC_ARGS # class for arguments when work with clear C-code
|
|
223
|
+
def count
|
|
224
|
+
RubimCode::UserVariable.new("argc", "int")
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def [](index)
|
|
228
|
+
RubimCode::UserVariable.new("argv[#{index}]", "int")
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
end
|
|
233
|
+
# === END class RubimCode === #
|
|
234
|
+
|
data/lib/version.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rubimc
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Evgeny Danilov
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2016-04-27 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Ruby compiler and framework for microcontrollers like AVR, PIC & STM.
|
|
14
|
+
It was designed to simplify the process of programming microcontrollers, but can
|
|
15
|
+
also be used as an clear С-code generator that can be compiled with gcc
|
|
16
|
+
email: jmelkor@rambler.ru
|
|
17
|
+
executables:
|
|
18
|
+
- rubimc
|
|
19
|
+
extensions: []
|
|
20
|
+
extra_rdoc_files: []
|
|
21
|
+
files:
|
|
22
|
+
- LICENSE.md
|
|
23
|
+
- README.md
|
|
24
|
+
- bin/rubimc
|
|
25
|
+
- lib/rubimc.rb
|
|
26
|
+
- lib/rubimc/control_structures.rb
|
|
27
|
+
- lib/rubimc/controllers.rb
|
|
28
|
+
- lib/rubimc/init_var.rb
|
|
29
|
+
- lib/rubimc/io_ports.rb
|
|
30
|
+
- lib/rubimc/mcu/avr/attiny13.rb
|
|
31
|
+
- lib/rubimc/mcu/avr/avr_controller.rb
|
|
32
|
+
- lib/rubimc/preprocessor.rb
|
|
33
|
+
- lib/rubimc/printer.rb
|
|
34
|
+
- lib/rubimc/ruby_classes.rb
|
|
35
|
+
- lib/version.rb
|
|
36
|
+
homepage: https://github.com/jmelkor/RubimC
|
|
37
|
+
licenses:
|
|
38
|
+
- MIT
|
|
39
|
+
metadata: {}
|
|
40
|
+
post_install_message:
|
|
41
|
+
rdoc_options: []
|
|
42
|
+
require_paths:
|
|
43
|
+
- lib
|
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
requirements: []
|
|
55
|
+
rubyforge_project:
|
|
56
|
+
rubygems_version: 2.4.5
|
|
57
|
+
signing_key:
|
|
58
|
+
specification_version: 4
|
|
59
|
+
summary: 'RubimC: Framework for MCU - 0.2.1'
|
|
60
|
+
test_files: []
|