bel_parser 1.0.0.alpha.57-java → 1.0.0.alpha.58-java

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60beaba7ec588b49f39e177c3c2ae31cdf9c48c6
4
- data.tar.gz: 47feab6424d1532624d3841f00ae126fd88cc5ff
3
+ metadata.gz: 2e51f1fc03c4170844be82ca4fd6635b4de3d7f3
4
+ data.tar.gz: c33c9a32f0849c0778e715c3e4a305769b21306a
5
5
  SHA512:
6
- metadata.gz: 258561f22b61be0fdd2d850a2d43b83a4e4248a05ef19a945a755a6826ef72665542ff997ae489bbce2297ee807b529dcbbc2762c57168e586ef5046d93b59bf
7
- data.tar.gz: 399dfffc0c57a4d1915a8962e78e81ae163ce214308957dff0f2b4f0386061dd910b578857d66af9a5319ba24e102aa2052ddabf490843644a2619f01d7ddef9
6
+ metadata.gz: aa0e04a26cd31039e0681cefb9576b748e6f87f31002b5899f5be742dcfc7e2bb1967b36ea3f2d03f6eb322775b9dda8d16fd27b51db26fd98fad492bde3d30b
7
+ data.tar.gz: eadf57c356bc3679f19da497ef82f069a1a6a294ebea3f1a053acbb5c215412049c581c8168353d9025917bd82c2cf769be63f90309d7d0cc51ce3a8720aca0d
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.alpha.57
1
+ 1.0.0.alpha.58
data/bin/bel2_debug_ast CHANGED
@@ -33,7 +33,6 @@ io =
33
33
  else
34
34
  $stdin
35
35
  end
36
- puts options[:complete]
37
36
 
38
37
  class ::AST::Node
39
38
 
data/bin/bel2_upgrade ADDED
@@ -0,0 +1,74 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift(
3
+ File.join(File.expand_path(File.dirname(__FILE__)), '..', 'lib'))
4
+
5
+ require 'optparse'
6
+ require 'bel_parser'
7
+
8
+ options = {}
9
+ OptionParser.new do |opts|
10
+ opts.banner = <<-USAGE.gsub(/^ {4}/, '')
11
+ Convert BEL 1.0 to 2.0.
12
+
13
+ Read from a BEL Script file.
14
+ usage: #$PROGRAM_NAME --file [FILE]
15
+
16
+ Read BEL Script from standard input.
17
+ usage: #$PROGRAM_NAME
18
+ USAGE
19
+
20
+ opts.on('-f', '--file FILE', 'BEL script file to read.') do |bel|
21
+ options[:file] = bel
22
+ end
23
+ end.parse!
24
+
25
+ file = options[:file]
26
+ io =
27
+ if file
28
+ File.open(file, external_encoding: 'UTF-8')
29
+ else
30
+ $stdin
31
+ end
32
+
33
+ CONVERSION_TYPES = [
34
+ :simple_statement,
35
+ :nested_statement,
36
+ :observed_term
37
+ ]
38
+
39
+ spec = BELParser::Language.specification('1.0')
40
+ upgrades = spec.upgrades.map(&:new)
41
+
42
+ include BELParser::Parsers
43
+ include BELParser::Parsers::AST::Sexp
44
+
45
+ puts serialize(
46
+ document_property(
47
+ name(
48
+ identifier('BELVersion')),
49
+ value(
50
+ string('"2.0"'))))
51
+ BELParser::ASTGenerator.new(io).each do |result|
52
+ line_number, line, asts = result
53
+
54
+ document_property =
55
+ asts.find { |ast|
56
+ ast && ast.type == :document_property
57
+ }
58
+ next if document_property && document_property.name.identifier.string_literal.downcase == 'belversion'
59
+
60
+ ast =
61
+ asts.find do |ast|
62
+ ast && CONVERSION_TYPES.include?(ast.type)
63
+ end
64
+
65
+ if ast
66
+ ast =
67
+ upgrades.reduce(ast) do |ast, upgrade|
68
+ upgrade.process(ast)
69
+ end
70
+ puts serialize(ast)
71
+ else
72
+ puts line
73
+ end
74
+ end
@@ -8,7 +8,7 @@ module BELParser
8
8
 
9
9
  def self.load_version_path(version_path)
10
10
  base_path = File.expand_path(File.dirname(__FILE__)) + File::SEPARATOR
11
- ['return_types', 'value_encodings', 'functions', 'relationships']
11
+ ['return_types', 'value_encodings', 'functions', 'relationships', 'upgrades']
12
12
  .each do |set|
13
13
  Dir[File.join(base_path, version_path, set, '*.rb')]
14
14
  .each do |ruby_file|
@@ -25,6 +25,7 @@ module BELParser
25
25
  load_value_encodings(version_module)
26
26
  load_functions(version_module)
27
27
  load_relationships(version_module)
28
+ load_upgrades(version_module)
28
29
  end
29
30
 
30
31
  private
@@ -77,6 +78,17 @@ module BELParser
77
78
  @indexed_relationships = index_long_short(@relationships)
78
79
  assign_relationship_categories(@relationships)
79
80
  end
81
+
82
+ def load_upgrades(version_module)
83
+ # Collect upgrades
84
+ upgrade_classes =
85
+ version_module::Upgrades.constants.collect do |symbol|
86
+ const = version_module::Upgrades.const_get(symbol)
87
+ const if
88
+ const.include?(BELParser::Language::TermTransformation)
89
+ end
90
+ @upgrades = upgrade_classes.compact
91
+ end
80
92
  end
81
93
  end
82
94
  end
@@ -45,6 +45,10 @@ module BELParser
45
45
  end
46
46
  end
47
47
 
48
+ def upgrades
49
+ @upgrades.freeze
50
+ end
51
+
48
52
  attr_reader :causal_relationships
49
53
  attr_reader :correlative_relationships
50
54
  attr_reader :decreasing_relationships
@@ -0,0 +1,88 @@
1
+ require 'bel_parser/vendor/ast'
2
+ require 'bel_parser/parsers/ast/node'
3
+
4
+ module BELParser
5
+ module Language
6
+ module TermTransformation
7
+ include AST::Processor::Mixin
8
+ include BELParser::Parsers::AST::Sexp
9
+
10
+ ACTIVITIES = {
11
+ 'cat' => 'cat',
12
+ 'catalyticActivity' => 'cat',
13
+ 'chap' => 'chap',
14
+ 'chaperoneActivity' => 'chap',
15
+ 'gtp' => 'gtp',
16
+ 'gtpBoundActivity' => 'gtp',
17
+ 'kin' => 'kin',
18
+ 'kinaseActivity' => 'kin',
19
+ 'act' => 'act',
20
+ 'molecularActivity' => 'act',
21
+ 'pep' => 'pep',
22
+ 'peptidaseActivity' => 'pep',
23
+ 'phos' => 'phos',
24
+ 'phosphataseActivity' => 'phos',
25
+ 'ribo' => 'ribo',
26
+ 'ribosylationActivity' => 'ribo',
27
+ 'tscript' => 'tscript',
28
+ 'transcriptionalActivity' => 'tscript',
29
+ 'tport' => 'tport',
30
+ 'transportActivity' => 'tport'
31
+ }
32
+
33
+ PMODTYPES = {
34
+ 'P' => 'Ph',
35
+ 'A' => 'Ac',
36
+ 'F' => 'Farn',
37
+ 'G' => 'Glyco',
38
+ 'H' => 'Hy',
39
+ 'M' => 'Me',
40
+ 'R' => 'ADPRib',
41
+ 'S' => 'Sumo',
42
+ 'U' => 'Ub'
43
+ }
44
+
45
+ def on_observed_term(observed_term_node)
46
+ observed_term_node.updated([process(observed_term_node.statement)])
47
+ end
48
+
49
+ def on_nested_statement(nested_statement_node)
50
+ nested_statement_node.updated([process(nested_statement_node.statement)])
51
+ end
52
+
53
+ def on_simple_statement(simple_statement_node)
54
+ simple_statement_node.updated([process(simple_statement_node.statement)])
55
+ end
56
+
57
+ def on_statement(statement_node)
58
+ statement_node.updated([process(statement_node.subject), statement_node.relationship, process(statement_node.object), statement_node.comment])
59
+ end
60
+
61
+ def on_subject(subject_node)
62
+ subject_node.updated([process(subject_node.term)])
63
+ end
64
+
65
+ def on_object(object_node)
66
+ return if object_node.nil?
67
+ object_node.updated([process(object_node.child)])
68
+ end
69
+
70
+ def on_argument(argument_node)
71
+ argument_node.updated([process(argument_node.child)])
72
+ end
73
+
74
+ def on_function(function_node)
75
+ function_node.updated([process(function_node.identifier)])
76
+ end
77
+
78
+ # Called when visiting nodes of type +term+.
79
+ def on_term(term_node)
80
+ term_node.updated([process(term_node.function), term_node.arguments.map! {|arg| process(arg)}].flatten())
81
+ end
82
+
83
+ def collapse(node)
84
+ node.to_sexp(indent=0).gsub("\n", '')
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,48 @@
1
+ require 'bel_parser/vendor/ast'
2
+ require 'bel_parser/parsers/ast/node'
3
+ require 'bel_parser/language/term_transformation'
4
+
5
+ module BELParser
6
+ module Language
7
+ module Version1_0
8
+ module Upgrades
9
+ class ActivityTransformation
10
+ include AST::Processor::Mixin
11
+ include BELParser::Parsers::AST::Sexp
12
+ include BELParser::Language::TermTransformation
13
+
14
+ def on_term(term_node)
15
+ if ACTIVITIES.keys.include?(term_node.function.identifier.string_literal)
16
+ term_node.updated([
17
+ # activity function
18
+ process(term_node.function),
19
+ # original arguments
20
+ term_node.arguments.map! {|arg| argument(process(arg.child))},
21
+ # additional molecularActivity argument
22
+ add_molecular_activity(ACTIVITIES[term_node.function.identifier.string_literal])
23
+ ].flatten)
24
+
25
+ end
26
+ end
27
+
28
+ def add_molecular_activity(_activity_identifier)
29
+ argument(
30
+ term(
31
+ function(
32
+ identifier('molecularActivity')),
33
+ argument(
34
+ parameter(
35
+ prefix(
36
+ identifier('default')),
37
+ value(
38
+ identifier(_activity_identifier))))))
39
+ end
40
+
41
+ def on_function(function_node)
42
+ function_node.updated([identifier('activity')])
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,69 @@
1
+ require 'bel_parser/vendor/ast'
2
+ require 'bel_parser/parsers/ast/node'
3
+ require 'bel_parser/language/term_transformation'
4
+
5
+ module BELParser
6
+ module Language
7
+ module Version1_0
8
+ module Upgrades
9
+ class FusionTransformation
10
+ include AST::Processor::Mixin
11
+ include BELParser::Parsers::AST::Sexp
12
+ include BELParser::Language::TermTransformation
13
+
14
+ def fusion_node?(term_node)
15
+ fusion_func = false
16
+
17
+ fusionable_func =
18
+ [
19
+ 'p', 'proteinAbundance',
20
+ 'r', 'rnaAbundance',
21
+ 'g', 'geneAbundance'
22
+ ].include?(term_node.function.identifier.string_literal)
23
+ return false unless fusionable_func
24
+
25
+ if term_node.arguments[1] && term_node.arguments[1].child.respond_to?('function')
26
+ ['fus', 'fusion'].include?(term_node.arguments[1].child.function.identifier.string_literal)
27
+ else
28
+ false
29
+ end
30
+ end
31
+
32
+ def on_term(term_node)
33
+ if fusion_node?(term_node)
34
+ fusionable_func = term_node.function.identifier.string_literal
35
+ parameter = term_node.arguments[0].child
36
+
37
+ first_prefix = parameter.prefix.identifier.string_literal
38
+ first_value = parameter.value.children[0].string_literal
39
+ parameter = term_node.arguments[1].child.arguments[0].child
40
+ second_prefix = parameter.prefix.identifier.string_literal
41
+ second_value = parameter.value.children[0].string_literal
42
+
43
+ term(
44
+ function(
45
+ identifier(fusionable_func)),
46
+ term(
47
+ function(
48
+ identifier('fus')),
49
+ argument(
50
+ parameter(
51
+ prefix(
52
+ identifier(first_prefix)),
53
+ value(
54
+ identifier(first_value)))),
55
+ argument(
56
+ parameter(
57
+ prefix(
58
+ identifier(second_prefix)),
59
+ value(
60
+ identifier(second_value))))))
61
+ else
62
+ term_node.updated([process(term_node.function), term_node.arguments.map! {|arg| process(arg)}].flatten())
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,36 @@
1
+ require 'bel_parser/vendor/ast'
2
+ require 'bel_parser/parsers/ast/node'
3
+ require 'bel_parser/language/term_transformation'
4
+
5
+ module BELParser
6
+ module Language
7
+ module Version1_0
8
+ module Upgrades
9
+ class ProteinModificationTransformation
10
+ include AST::Processor::Mixin
11
+ include BELParser::Parsers::AST::Sexp
12
+ include BELParser::Language::TermTransformation
13
+
14
+ def on_term(term_node)
15
+ if ['pmod', 'proteinmodification'].include?(term_node.function.identifier.string_literal)
16
+ # straightforward replacement of first argument to pmod with pmodtype value
17
+ term_node.updated([term_node.function, update_pmod(term_node.arguments[0]), term_node.arguments[1], term_node.arguments[2] ].flatten)
18
+ else
19
+ term_node.updated([process(term_node.function), term_node.arguments.map! {|arg| process(arg)}].flatten())
20
+ end
21
+ end
22
+
23
+ def update_pmod(argument_node)
24
+ param_value = argument_node.child.value.children[0].string_literal
25
+ argument(
26
+ parameter(
27
+ prefix(
28
+ identifier('default')),
29
+ value(
30
+ identifier(PMODTYPES[param_value]))))
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,40 @@
1
+ require 'bel_parser/vendor/ast'
2
+ require 'bel_parser/parsers/ast/node'
3
+ require 'bel_parser/language/term_transformation'
4
+
5
+ module BELParser
6
+ module Language
7
+ module Version1_0
8
+ module Upgrades
9
+ class TranslocationTransformation
10
+ include AST::Processor::Mixin
11
+ include BELParser::Parsers::AST::Sexp
12
+ include BELParser::Language::TermTransformation
13
+
14
+ def on_term(term_node)
15
+ if ['tloc', 'translocation'].include?(term_node.function.identifier.string_literal)
16
+ term_node.updated([term_node.function, term_node.arguments[0], add_loc_func(term_node.arguments[1], 'fromLoc'), add_loc_func(term_node.arguments[2], 'toLoc') ].flatten)
17
+ else
18
+ term_node.updated([process(term_node.function), term_node.arguments.map! {|arg| process(arg)}].flatten())
19
+ end
20
+ end
21
+
22
+ def add_loc_func(argument_node, function_name)
23
+ prefix_name = argument_node.child.prefix.children[0].string_literal
24
+ value_name = argument_node.child.value.children[0].string_literal
25
+ argument(
26
+ term(
27
+ function(
28
+ identifier(function_name)),
29
+ argument(
30
+ parameter(
31
+ prefix(
32
+ identifier(prefix_name)),
33
+ value(
34
+ identifier(value_name))))))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,166 @@
1
+ require 'bel_parser/vendor/ast'
2
+ require 'bel_parser/parsers/ast/node'
3
+ require 'bel_parser/language/term_transformation'
4
+
5
+ module BELParser
6
+ module Language
7
+ module Version1_0
8
+ module Upgrades
9
+ class VariationTransformation
10
+ include AST::Processor::Mixin
11
+ include BELParser::Parsers::AST::Sexp
12
+ include BELParser::Language::TermTransformation
13
+
14
+ def on_term(term_node)
15
+ is_parent_func = ['p', 'proteinAbundance', 'r', 'rnaAbundance', 'g', 'geneAbundance'].include?(term_node.function.identifier.string_literal)
16
+ parent_func = term_node.function.identifier.string_literal
17
+
18
+ unless is_parent_func
19
+ return term_node.updated([process(term_node.function), term_node.arguments.map! {|arg| process(arg)}].flatten())
20
+ end
21
+
22
+ if term_node.arguments[0].parameter?
23
+ param_prefix = term_node.arguments[0].child.prefix.identifier.string_literal
24
+ param_value = term_node.arguments[0].child.value.children[0].string_literal
25
+ end
26
+
27
+ if term_node.arguments[1].respond_to?('child') && term_node.arguments[1].child.respond_to?('function') && term_node.arguments[1].child.function
28
+ is_sub_func = ['sub', 'substitution'].include?(term_node.arguments[1].child.function.identifier.string_literal)
29
+ is_trunc_func = ['trunc', 'truncation'].include?(term_node.arguments[1].child.function.identifier.string_literal)
30
+ end
31
+
32
+ if is_sub_func || is_trunc_func
33
+ if is_parent_func && is_sub_func
34
+ variant_node = term_node.arguments[1].child
35
+ ref = variant_node.arguments[0].child.value.children[0].string_literal
36
+ loc = variant_node.arguments[1].child.value.children[0].string_literal
37
+ alt = variant_node.arguments[2].child.value.children[0].string_literal
38
+
39
+ if ['p'].include?(parent_func)
40
+ return protein_sub_conversion(parent_func, param_prefix, param_value, ref, loc, alt)
41
+ else
42
+ return dna_sub_conversion(parent_func, param_prefix, param_value, ref, loc, alt)
43
+ end
44
+ end
45
+
46
+ if is_parent_func && is_trunc_func
47
+
48
+ variant_node = term_node.arguments[1].child
49
+ loc = variant_node.arguments[0].child.value.children[0].string_literal
50
+
51
+ if ['p'].include?(parent_func)
52
+ return protein_trunc_conversion(parent_func, param_prefix, param_value, loc)
53
+ else
54
+ return dna_trunc_conversion(parent_func, param_prefix, param_value, loc)
55
+ end
56
+
57
+ end
58
+ else
59
+ term_node.updated([process(term_node.function), term_node.arguments.map! {|arg| process(arg)}].flatten())
60
+ end
61
+ end
62
+
63
+ def protein_sub_conversion(parent_func, param_prefix, param_value, ref, loc, alt)
64
+ term(
65
+ function(
66
+ identifier(parent_func)),
67
+ argument(
68
+ parameter(
69
+ prefix(
70
+ identifier(param_prefix)),
71
+ value(
72
+ identifier(param_value)))),
73
+ argument(
74
+ term(
75
+ function(
76
+ identifier('var')),
77
+ argument(
78
+ parameter(
79
+ value(
80
+ identifier(%("#{parent_func}.#{ref}#{loc}#{alt}"))))))))
81
+ end
82
+
83
+ def dna_sub_conversion(parent_func, param_prefix, param_value, ref, loc, alt) # and RNA
84
+ converted_parent_func =
85
+ case parent_func
86
+ when 'p', 'proteinAbundance'
87
+ 'p'
88
+ when 'g', 'geneAbundance'
89
+ 'c'
90
+ when 'r', 'rnaAbundance'
91
+ 'r'
92
+ end
93
+
94
+ term(
95
+ function(
96
+ identifier(parent_func)),
97
+ argument(
98
+ parameter(
99
+ prefix(
100
+ identifier(param_prefix)),
101
+ value(
102
+ identifier(param_value)))),
103
+ argument(
104
+ term(
105
+ function(
106
+ identifier('var')),
107
+ argument(
108
+ parameter(
109
+ value(
110
+ identifier(%("#{converted_parent_func}.#{loc}#{ref}>#{alt}"))))))))
111
+ end
112
+
113
+ def protein_trunc_conversion(parent_func, param_prefix, param_value, loc)
114
+ term(
115
+ function(
116
+ identifier(parent_func)),
117
+ argument(
118
+ parameter(
119
+ prefix(
120
+ identifier(param_prefix)),
121
+ value(
122
+ identifier(param_value)))),
123
+ argument(
124
+ term(
125
+ function(
126
+ identifier('var')),
127
+ argument(
128
+ parameter(
129
+ value(
130
+ identifier(%("#{parent_func}.#{loc}*"))))))))
131
+ end
132
+
133
+ def dna_trunc_conversion(parent_func, param_prefix, param_value, loc) # and RNA
134
+ converted_parent_func =
135
+ case parent_func
136
+ when 'p', 'proteinAbundance'
137
+ 'p'
138
+ when 'g', 'geneAbundance'
139
+ 'c'
140
+ when 'r', 'rnaAbundance'
141
+ 'r'
142
+ end
143
+
144
+ term(
145
+ function(
146
+ identifier(parent_func)),
147
+ argument(
148
+ parameter(
149
+ prefix(
150
+ identifier(param_prefix)),
151
+ value(
152
+ identifier(param_value)))),
153
+ argument(
154
+ term(
155
+ function(
156
+ identifier('var')),
157
+ argument(
158
+ parameter(
159
+ value(
160
+ identifier(%("#{converted_parent_func}.#{loc}*"))))))))
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
@@ -5,6 +5,7 @@ require_relative 'language/semantics'
5
5
  require_relative 'language/signature'
6
6
  require_relative 'language/specification'
7
7
  require_relative 'language/expression_validator'
8
+ require_relative 'language/term_transformation'
8
9
 
9
10
  module BELParser
10
11
  # Language defines the concepts needed to define, represent, and
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bel_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.alpha.57
4
+ version: 1.0.0.alpha.58
5
5
  platform: java
6
6
  authors:
7
7
  - Anthony Bargnesi
@@ -42,6 +42,7 @@ dependencies:
42
42
  description: Implements language versions 1.0 and 2.0.
43
43
  email: abargnesi@selventa.com
44
44
  executables:
45
+ - bel2_upgrade
45
46
  - bel2_debug_ast
46
47
  - bel2_validator
47
48
  - bel_script_reader
@@ -54,6 +55,7 @@ files:
54
55
  - README.md
55
56
  - VERSION
56
57
  - bin/bel2_debug_ast
58
+ - bin/bel2_upgrade
57
59
  - bin/bel2_validator
58
60
  - bin/bel_script_reader
59
61
  - lib/bel/translator/plugins/bel_script.rb
@@ -113,6 +115,7 @@ files:
113
115
  - lib/bel_parser/language/syntax_function.rb
114
116
  - lib/bel_parser/language/syntax_result.rb
115
117
  - lib/bel_parser/language/syntax_warning.rb
118
+ - lib/bel_parser/language/term_transformation.rb
116
119
  - lib/bel_parser/language/version1_0.rb
117
120
  - lib/bel_parser/language/version1_0/functions/abundance.rb
118
121
  - lib/bel_parser/language/version1_0/functions/biological_process.rb
@@ -199,6 +202,11 @@ files:
199
202
  - lib/bel_parser/language/version1_0/return_types/transcriptional_activity.rb
200
203
  - lib/bel_parser/language/version1_0/return_types/transport_activity.rb
201
204
  - lib/bel_parser/language/version1_0/return_types/truncation.rb
205
+ - lib/bel_parser/language/version1_0/upgrades/activity_transformation.rb
206
+ - lib/bel_parser/language/version1_0/upgrades/fusion_transformation.rb
207
+ - lib/bel_parser/language/version1_0/upgrades/protein_modification_transformation.rb
208
+ - lib/bel_parser/language/version1_0/upgrades/translocation_transformation.rb
209
+ - lib/bel_parser/language/version1_0/upgrades/variation_transformation.rb
202
210
  - lib/bel_parser/language/version1_0/value_encodings/abundance.rb
203
211
  - lib/bel_parser/language/version1_0/value_encodings/any.rb
204
212
  - lib/bel_parser/language/version1_0/value_encodings/biological_process.rb