rbbt-entities 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rbbt/entity.rb CHANGED
@@ -27,6 +27,95 @@ module Entity
27
27
  Entity.formats[format] = self
28
28
  end
29
29
  end
30
+
31
+ def clean_annotations
32
+ case
33
+ when Array === self
34
+ self.annotated_array_clean_collect{|e| e.respond_to?(:clean_annotations)? e.clean_annotations : e}
35
+ when String === self
36
+ "" << self
37
+ end
38
+ end
39
+
40
+ def consolidate
41
+ self.inject(nil){|acc,e|
42
+ if acc.nil?
43
+ acc = e
44
+ else
45
+ acc.concat e
46
+ end
47
+ }
48
+ end
49
+ end
50
+ end
51
+
52
+ def property(name, &block)
53
+ case
54
+ when (Hash === name and name.size == 1)
55
+ name, type = name.collect.first
56
+ when (String === name or Symbol === name)
57
+ type = :both
58
+ else
59
+ raise "Format of name ( => type) not understood: #{name.inspect}"
60
+ end
61
+
62
+ name = name.to_s unless String === name
63
+
64
+ case type
65
+ when :both
66
+ self.module_eval do define_method name, &block end
67
+ when :array
68
+ self.module_eval do
69
+ ary_name = "_ary_" << name
70
+ define_method ary_name, &block
71
+ define_method name do |*args|
72
+ raise "Method #{ name } only defined for array" unless Array === self
73
+ self.send(ary_name, *args)
74
+ end
75
+ end
76
+ when :single
77
+ self.module_eval do
78
+ single_name = "_single_" << name
79
+ define_method single_name, &block
80
+ define_method name do |*args|
81
+ raise "Method #{ name } not defined for array" if Array === self
82
+ self.send(single_name, *args)
83
+ end
84
+ end
85
+ when :single2array
86
+ self.module_eval do
87
+ single_name = "_single_" << name
88
+ define_method single_name, &block
89
+ define_method name do |*args|
90
+ if Array === self
91
+ collect{|e| e.send(single_name, *args)}
92
+ else
93
+ self.send(single_name, *args)
94
+ end
95
+ end
96
+ end
97
+ when :array2single
98
+ self.module_eval do
99
+ ary_name = "_ary_" << name
100
+ define_method ary_name, &block
101
+ define_method name do |*args|
102
+ case
103
+ when Array === self
104
+ self.send(ary_name, *args)
105
+ when (Array === self.container and self.container.respond_to? ary_name)
106
+ res = self.container.send(ary_name, *args)
107
+ if Hash === res
108
+ res[self]
109
+ else
110
+ pos = self.container.index self
111
+ res[pos]
112
+ end
113
+ else
114
+ res = self.make_list.send(ary_name, *args)
115
+ Hash === res ? res[self] : res[0]
116
+ end
117
+ end
118
+ end
30
119
  end
31
120
  end
32
121
  end
@@ -0,0 +1,37 @@
1
+ require 'rbbt/entity'
2
+ require 'rbbt/workflow'
3
+ require 'rbbt/sources/organism'
4
+ require 'rbbt/entity/gene'
5
+
6
+ Workflow.require_workflow "Sequence"
7
+
8
+ module CNV
9
+ extend Entity
10
+ self.annotation :jobname
11
+ self.annotation :organism
12
+
13
+ self.format = "Copy Number Variation"
14
+
15
+ property :variation => :single2array do
16
+ self.split(":").last
17
+ end
18
+
19
+ property :loss? => :array2single do
20
+ @loss ||= self.variation.collect{|v| v =~/loss/i}
21
+ end
22
+
23
+ property :gain? => :array2single do
24
+ @gain ||= self.variation.collect{|v| v =~/gain/i}
25
+ end
26
+
27
+ property :genes => :array2single do
28
+ @genes ||= begin
29
+ genes = Sequence.job(:genes_at_genomic_ranges, jobname, :organism => organism, :ranges => self).run
30
+ genes.unnamed = true
31
+ genes = genes.values_at *self
32
+ Gene.setup(genes, "Ensembl Gene ID", organism)
33
+ end
34
+ end
35
+
36
+ end
37
+
@@ -2,6 +2,8 @@ require 'rbbt/entity'
2
2
  require 'rbbt/workflow'
3
3
  require 'rbbt/sources/organism'
4
4
  require 'rbbt/sources/entrez'
5
+ require 'rbbt/entity/protein'
6
+ require 'rbbt/entity/pmid'
5
7
 
6
8
  Workflow.require_workflow "Translation"
7
9
 
@@ -11,50 +13,96 @@ module Gene
11
13
  self.annotation :format
12
14
  self.annotation :organism
13
15
 
14
- self.format = Organism::Hsa.identifiers.all_fields
16
+ self.format = Organism::Hsa.identifiers.all_fields - ["Ensembl Protein ID", "Ensembl Transcript ID"]
15
17
 
16
- def name
17
- to "Associated Gene Name"
18
+ property :to! => :array2single do |new_format|
19
+ return self if format == new_format
20
+ Gene.setup(Translation.job(:tsv_translate, "", :organism => organism, :genes => self, :format => new_format).exec.values_at(*self), new_format, organism)
18
21
  end
19
22
 
20
- def description
21
- if Array === self
22
- to("Entrez Gene ID").collect{|id| gene = Entrez.get_gene(id); gene.nil? ? nil : gene.summary}
23
- else
24
- gene = Entrez.get_gene(to("Entrez Gene ID"))
25
- gene.nil? ? nil : gene.summary
26
- end
23
+ property :to => :array2single do |new_format|
24
+ return self if format == new_format
25
+ to!(new_format).collect!{|v| v.nil? ? nil : v.first}
27
26
  end
28
27
 
29
- def to!(new_format)
30
- if Array === self
31
- Gene.setup(Translation.job(:tsv_translate, "", :organism => organism, :genes => self, :format => new_format).exec.values_at(*self), new_format, organism)
32
- else
33
- Gene.setup(Translation.job(:tsv_translate, "", :organism => organism, :genes => [self], :format => new_format).exec[self], new_format, organism)
34
- end
28
+ property :ensembl => :array2single do
29
+ @ensembl ||= to "Ensembl Gene ID"
35
30
  end
36
31
 
37
- def to(new_format)
38
- return self if format == new_format
39
- if Array === self
40
- to!(new_format).collect!{|v| v.nil? ? nil : v.first}
41
- else
42
- v = to!(new_format)
43
- v.nil? ? nil : v.first
44
- end
32
+ property :entrez => :array2single do
33
+ @entrez ||= to "Entrez Gene ID"
45
34
  end
46
35
 
47
- def self2pfam
48
- index = Organism.gene_pfam(organism).tsv :type => :flat, :persist => true
49
- if Array === self
50
- index.values_at(*self).flatten
51
- else
52
- index[self]
53
- end
36
+
37
+ property :name => :array2single do
38
+ @name ||= to "Associated Gene Name"
39
+ end
40
+
41
+ property :chr_start => :array2single do
42
+ @chr_start = begin
43
+ Organism.gene_positions(organism).tsv(:persist => true, :type => :single, :cast => :to_i, :fields => ["Gene Start"]).values_at *self
44
+ end
45
+ end
46
+
47
+ property :go_bp_terms => :array2single do
48
+ @go_bp_terms ||= Organism.gene_go_bp(organism).tsv(:persist => true, :key_field => "Ensembl Gene ID", :fields => ["GO ID"], :type => :flat).values_at *self.ensembl
49
+ end
50
+
51
+ property :long_name => :single2array do
52
+ gene = Entrez.get_gene(to("Entrez Gene ID"))
53
+ gene.nil? ? nil : gene.description.flatten.first
54
+ end
55
+
56
+ property :description => :single2array do
57
+ gene = Entrez.get_gene(to("Entrez Gene ID"))
58
+ gene.nil? ? nil : gene.summary.flatten.first
59
+ end
60
+
61
+ property :transcripts => :array2single do
62
+ gene_transcripts = Organism.gene_transcripts(organism).tsv :persist => true
63
+ gene_transcripts.unnamed = true
64
+ res = gene_transcripts.values_at(*self.ensembl)
65
+ res.each{|l| Transcript.setup(l, "Ensembl Transcript ID", organism)}
66
+ res
67
+ end
68
+
69
+ property :proteins => :array2single do
70
+ @proteins ||= begin
71
+ transcripts = self.transcripts
72
+ all_transcripts = Transcript.setup(transcripts.flatten, "Ensembl Transcript ID", organism)
73
+ transcript2protein = nil
74
+
75
+ transcript2protein = Misc.process_to_hash(all_transcripts){|list|
76
+ list.protein
77
+ }
78
+
79
+ res = nil
80
+ res = transcripts.collect{|list|
81
+ Protein.setup(transcript2protein.values_at(*list), "Ensembl Protein ID", organism)
82
+ }
83
+
84
+ res.each{|l|
85
+ }
86
+ res
87
+ end
54
88
  end
55
89
 
56
- def chromosome
90
+ property :max_transcript_length => :array2single do
91
+ transcripts.collect{|list| list.sequence_length.compact.max}
92
+ end
93
+
94
+ property :max_protein_length => :array2single do
95
+ @max_protein_length ||= begin
96
+ proteins = self.proteins
97
+ all_proteins = Protein.setup(proteins.flatten, "Ensembl Protein ID", organism)
98
+ lengths = Misc.process_to_hash(all_proteins){|list| list.sequence_length}
99
+ proteins.collect{|list| lengths.values_at(*list).compact.max}
100
+ end
101
+ end
102
+
103
+ property :chromosome => :array2single do
57
104
  chr = Organism.gene_positions(organism).tsv :fields => ["Chromosome Name"], :type => :single, :persist => true
105
+ chr.unnamed = true
58
106
  if Array === self
59
107
  to("Ensembl Gene ID").collect do |gene|
60
108
  chr[gene]
@@ -64,39 +112,63 @@ module Gene
64
112
  end
65
113
  end
66
114
 
67
- def range
115
+ property :range => :array2single do
68
116
  pos = Organism.gene_positions(organism).tsv :fields => ["Gene Start", "Gene End"], :type => :list, :persist => true, :cast => :to_i
69
- if Array === self
70
- to("Ensembl Gene ID").collect do |gene|
71
- next if not pos.include? gene
72
- Range.new *pos[gene]
73
- end
74
- else
75
- return nil if not pos.include? to("Ensembl Gene ID")
76
- Range.new *pos[to("Ensembl Gene ID")]
117
+ to("Ensembl Gene ID").collect do |gene|
118
+ next if not pos.include? gene
119
+ Range.new *pos[gene]
77
120
  end
78
121
  end
79
122
 
123
+ property :articles => :array2single do
124
+ @articles ||= begin
125
+ PMID.setup(Organism.gene_pmids(organism).tsv(:persist => true, :fields => ["PMID"], :type => :flat).values_at *self.entrez)
126
+ end
127
+ end
80
128
  end
81
129
 
82
130
  module Transcript
83
131
  extend Entity
84
132
 
85
- def to!(new_format)
86
- if Array === self
87
- Gene.setup(Translation.job(:tsv_probe_translate, "", :organism => organism, :genes => self, :format => new_format).exec.values_at(*self), new_format, organism)
88
- else
89
- Gene.setup(Translation.job(:tsv_probe_translate, "", :organism => organism, :genes => [self], :format => new_format).exec[self], new_format, organism)
90
- end
133
+ self.annotation :format
134
+ self.annotation :organism
135
+
136
+ self.format = "Ensembl Transcript ID"
137
+
138
+ property :to! => :array2single do |new_format|
139
+ return self if format == new_format
140
+ Gene.setup(Translation.job(:tsv_probe_translate, "", :organism => organism, :genes => self, :format => new_format).exec.values_at(*self), new_format, organism)
91
141
  end
92
142
 
93
- def to(new_format)
143
+ property :to => :array2single do |new_format|
94
144
  return self if format == new_format
95
- if Array === self
96
- to!(new_format).collect{|v| v.nil? ? nil : v.first}
97
- else
98
- v = to!(new_format)
99
- v.nil? ? nil : v.first
100
- end
145
+ to!(new_format).collect!{|v| v.nil? ? nil : v.first}
146
+ end
147
+
148
+ def ensembl
149
+ to "Ensembl Transcript ID"
150
+ end
151
+
152
+
153
+ property :sequence => :array2single do
154
+ transcript_sequence = Organism.transcript_sequence(organism).tsv :persist => true
155
+ transcript_sequence.unnamed = true
156
+ transcript_sequence.values_at *self.ensembl
157
+ end
158
+
159
+ property :sequence_length => :array2single do
160
+ sequence.collect{|s|
161
+ s.nil? ? nil : s.length
162
+ }
163
+ end
164
+
165
+ property :protein => :array2single do
166
+ transcript_protein = Organism.transcripts(organism).tsv :single, :persist => true, :fields => ["Ensembl Protein ID"]
167
+ transcript_protein.unnamed = true
168
+
169
+ res = transcript_protein.values_at(*self.ensembl)
170
+ Protein.setup(res, "Ensembl Protein ID", organism)
171
+ res
101
172
  end
102
173
  end
174
+
@@ -0,0 +1,93 @@
1
+ require 'rbbt/entity'
2
+ require 'rbbt/workflow'
3
+ require 'rbbt/sources/organism'
4
+ require 'rbbt/mutation/mutation_assessor'
5
+ require 'rbbt/entity/protein'
6
+ require 'rbbt/entity/gene'
7
+ require 'rbbt/entity/mutated_isoform'
8
+
9
+ Workflow.require_workflow "Sequence"
10
+
11
+ module GenomicMutation
12
+ extend Entity
13
+ self.annotation :jobname
14
+ self.annotation :organism
15
+ self.annotation :watson
16
+
17
+ self.format = "Genomic Mutation"
18
+
19
+ property :score => :single2array do
20
+ self.split(":")[3].to_f
21
+ end
22
+
23
+
24
+ property :position => :single2array do
25
+ self.split(":")[1].to_i
26
+ end
27
+
28
+ property :offset_in_genes => :array2single do
29
+ gene2chr_start = Misc.process_to_hash(genes.flatten){|list| list.chr_start}
30
+ position.zip(genes).collect{|position, list|
31
+ list.collect{|gene|
32
+ next if not gene2chr_start.include? gene
33
+ [gene, position.to_i - gene2chr_start[gene]] * ":"
34
+ }.compact
35
+ }
36
+ end
37
+
38
+ property :genes => :array2single do
39
+ @genes ||= begin
40
+ genes = Sequence.job(:genes_at_genomic_positions, jobname, :organism => organism, :positions => self).run
41
+ genes.unnamed = true
42
+ genes = genes.values_at *self
43
+ Gene.setup(genes, "Ensembl Gene ID", organism)
44
+ end
45
+ end
46
+
47
+ property :mutated_isoforms => :array2single do
48
+ @mutated_isoforms ||= begin
49
+ res = Sequence.job(:mutated_isoforms_for_genomic_mutations, jobname, :watson => watson, :organism => organism, :mutations => self).run.values_at *self
50
+ res.each{|list| list.organism = organism}
51
+ res
52
+ end
53
+ end
54
+
55
+ property :exon_junctions do
56
+ @exon_junctions ||= Sequence.job(:exon_junctions_at_genomic_positions, jobname, :organism => organism, :positions => self).run.values_at *self
57
+ end
58
+
59
+ property :in_exon_junction? => :array2single do
60
+ exon_junctions.collect{|l| not l.nil? and not l.empty?}
61
+ end
62
+
63
+ property :over_gene? => :array2single do |gene|
64
+ @over_genes ||= {}
65
+ @over_genes[gene] ||= genes.clean_annotations.collect{|list| list.include? gene}
66
+ end
67
+
68
+ property :mutation_assessor_scores => :array2single do
69
+ @mutation_assessor_scores ||= begin
70
+ mutated_isoforms = self.mutated_isoforms
71
+ all_mutated_isoforms = MutatedIsoform.setup(mutated_isoforms.flatten.compact, organism)
72
+ mutated_isoform2damage_score = Misc.process_to_hash(all_mutated_isoforms){|list| all_mutated_isoforms.mutation_assessor_scores}
73
+
74
+ MutatedIsoform.setup(mutated_isoforms.collect{|list| list.nil? ? [] : mutated_isoform2damage_score.values_at(*list)}, organism)
75
+ end
76
+ end
77
+
78
+ property :truncated do
79
+ @truncated ||= begin
80
+ mutated_isoforms = self.mutated_isoforms
81
+ all_mutated_isoforms = MutatedIsoform.setup(mutated_isoforms.flatten.compact, organism)
82
+ mutated_isoform2truncated = Misc.process_to_hash(all_mutated_isoforms){|list| all_mutated_isoforms.truncated}
83
+ mutated_isoforms.collect{|list| list.nil? ? [] : mutated_isoform2truncated.values_at(*list)}
84
+ end
85
+ end
86
+
87
+ property :affected_exons => :array2single do
88
+ @affected_exons ||= begin
89
+ Sequence.job(:exons_at_genomic_positions, jobname, :organism => organism, :positions => self).run.values_at *self
90
+ end
91
+ end
92
+
93
+ end
@@ -1,186 +1,162 @@
1
- require 'rbbt/entity'
2
1
  require 'rbbt/workflow'
3
- require 'rbbt/sources/organism'
4
- require 'rbbt/mutation/mutation_assessor'
5
- require 'rbbt/entity/protein'
6
-
7
- Workflow.require_workflow "Sequence"
8
-
9
- module MutatedIsoform
10
- extend Entity
11
- self.annotation :organism
2
+ require 'rbbt/entity'
3
+ require 'rbbt/entity/genomic_mutation'
12
4
 
13
- self.format = "Mutated Isoform"
5
+ module Genotype
6
+ extend Workflow
14
7
 
15
- def protein
16
- if Array === self
17
- Protein.setup(self.collect{|mutation| mutation.split(":").first}, "Ensembl Protein ID", organism)
18
- else
19
- Protein.setup(self.split(":").first, "Ensembl Protein ID", organism)
8
+ if self.respond_to? :extended
9
+ class << self
10
+ alias prev_genotype_extended extended
20
11
  end
21
12
  end
22
13
 
23
- def ensembl_protein_image_url
24
- if Array === self
25
- self.collect{|e| e.ensembl_protein_image_url}
26
- else
27
- ensembl_url = if organism == "Hsa" then "www.ensembl.org" else "#{organism.sub(/.*\//,'')}.archive.ensembl.org" end
28
- "http://#{ensembl_url}/Homo_sapiens/Component/Transcript/Web/TranslationImage?db=core;p=#{protein};_rmd=d2a8;export=svg"
14
+ def self.extended(base)
15
+ prev_genotype_extended(base) if self.respond_to? :prev_genotype_extended
16
+ base.helper :genotype do
17
+ base
29
18
  end
30
19
  end
31
20
 
32
- ASTERISK = "*"[0]
33
- def single_type
34
- prot, change = self.split(":")
35
-
36
- case
37
- when change =~ /UTR/
38
- "UTR"
39
- when (change[0] == ASTERISK and not change[0] == change[-1])
40
- "NOSTOP"
41
- when (change[-1] == ASTERISK and not change[0] == change[-1])
42
- "NONSENSE"
43
- when change =~ /Indel/
44
- "INDEL"
45
- when change =~ /FrameShift/
46
- "FRAMESHIFT"
47
- when change[0] == change[-1]
48
- "SYNONYMOUS"
49
- else
50
- "MISS-SENSE"
51
- end
52
- end
53
-
54
- def ary_type
55
- self.collect{|mutation| mutation.single_type}
56
- end
57
-
21
+ module Cohort
22
+ extend Workflow
58
23
 
59
- def type
60
- Array === self ? ary_type : single_type
61
- end
62
-
63
- def filter(*types)
64
- list = self.zip(type).select do |mutation, type|
65
- types.include? type
66
- end.collect{|mutation, type| mutation}
67
-
68
- MutatedIsoform.setup(list, organism)
69
- end
70
-
71
- def self2mutation_assessor_prediction
72
- if Array === self
73
- filtered = filter "MISS-SENSE"
74
- correspondance = {}
75
- mutations = filtered.zip(filtered.protein.to "UniProt/SwissProt ID").collect do |mutation, uniprot|
76
- prot, change = mutation.split(":")
77
- next if uniprot.nil?
78
- uniprot_change = [uniprot, change]
79
- correspondance[uniprot_change] = mutation
80
- uniprot_change
81
- end.compact
82
-
83
- tsv = MutationAssessor.chunked_predict(mutations)
84
- return TSV.setup({}, :key_field => "Mutated Isoform", :fields => ["Func. Impact"]) if tsv.empty?
85
- tsv.add_field "Mutated Isoform" do |key, values|
86
- correspondance[key.split(" ")]
24
+ if self.respond_to? :extended
25
+ class << self
26
+ alias prev_genotype_cohort_extended extended
87
27
  end
88
- tsv.reorder "Mutated Isoform", ["Func. Impact"]
89
- else
90
- prot, change = mutation.split(":")
91
- uniprot = protein.to "UniProt/SwissProt ID"
92
- mutations = [uniprot, change]
93
-
94
- tsv = MutationAssessor.chunked_predict(mutations)
95
- tsv.add_field "Mutated Isoform" do |key, values|
96
- self
97
- end
98
- tsv.reorder "Mutated Isoform", ["Func. Impact"]
99
28
  end
100
- end
101
29
 
102
- def early_nonsense
103
- protein_sequences = Organism.protein_sequence(organism).tsv :persist => true, :type => :single
104
- filter("NONSENSE").select{|isoform_mutation|
105
- protein, mutation = isoform_mutation.split ":"
106
- if protein_sequences.include? protein
107
- mutation.match(/(\d+)/)[1].to_f < protein_sequences[protein].length.to_f * 0.7
108
- else
109
- false
30
+ def self.extended(base)
31
+ prev_genotype_cohort_extended(base) if self.respond_to? :prev_genotype_cohort_extended
32
+
33
+ class << base
34
+ attr_accessor :metagenotype
35
+
36
+ def jobname
37
+ if @jobname.nil?
38
+ @jobname ||= "Meta-genotype: " + self.collect{|g| g.jobname} * ", "
39
+ @jobname[100..-1] = " (etc; #{self.length} genotypes)" if @jobname.length > 100
40
+ end
41
+ @jobname
42
+ end
43
+
44
+ def metagenotype
45
+ if @metagenotype.nil?
46
+ @metagenotype = GenomicMutation.setup(self.dup.flatten, jobname, self[0].organism, self[0].watson)
47
+ @metagenotype.extend Genotype unless Genotype === @metagenotype
48
+ end
49
+ @metagenotype
50
+ end
51
+ end unless base.respond_to? :metagenotype
52
+
53
+ base.each do |genotype| genotype.extend Genotype unless Genotype === genotype end
54
+
55
+ base.helper :metagenotype do
56
+ base.metagenotype
110
57
  end
111
- }
112
- end
113
58
 
114
- def early_frameshifts
115
- protein_sequences = Organism.protein_sequence(organism).tsv :persist => true, :type => :single
116
- filter("FRAMESHIFT").select{|isoform_mutation|
117
- protein, mutation = isoform_mutation.split ":"
118
- if protein_sequences.include? protein
119
- mutation.match(/(\d+)/)[1].to_f < protein_sequences[protein].length.to_f * 0.7
120
- else
121
- false
59
+ base.helper :samples do
60
+ base
122
61
  end
123
- }
124
- end
125
62
 
126
- def damaged(options = {})
127
- options = Misc.add_defaults options, :mutation_assesor_cutoff => :medium, :non_sense => true, :frameshift => true
63
+ NamedArray.setup(base, base.collect{|base| base.jobname})
64
+ end
65
+
66
+ returns "Ensembl Gene ID"
67
+ task :all_affected_genes => :array do
68
+ set_info :organism, metagenotype.organism
69
+ samples.collect{|genotype| genotype.all_affected_genes}.flatten.uniq
70
+ end
128
71
 
129
- levels = [:low, :medium, :high].collect{|v| v.to_s}
130
- cutoff = levels.index options[:mutation_assesor_cutoff].to_s
72
+ returns "Ensembl Gene ID"
73
+ task :damaged_genes => :array do
74
+ set_info :organism, metagenotype.organism
75
+ samples.collect{|genotype| genotype.damaged_genes}.flatten.uniq
76
+ end
77
+
78
+
79
+ returns "Ensembl Gene ID"
80
+ task :recurrent_genes => :array do
81
+ set_info :organism, metagenotype.organism
82
+ count = Hash.new(0)
83
+ samples.each do |genotype| genotype.genes.flatten.uniq.each{|gene| count[gene] += 1} end
84
+ count.select{|gene, c| c > 1}.collect{|gene,c| gene.dup}
85
+ end
131
86
 
132
- predicted = self2mutation_assessor_prediction.select{|k, v|
133
- if v.nil?
134
- false
135
- else
136
- value = levels.index(v[0].to_s)
137
- value and value >= cutoff
87
+ %w(damaged_genes recurrent_genes all_affected_genes).each do |name|
88
+ define_method name do |*args|
89
+ @cache ||= {}
90
+ @cache[[name, args]] ||= self.job(name, self.jobname).run
138
91
  end
139
- }.collect{|k,v| k}
92
+ end
140
93
 
141
- predicted += early_nonsense if options[:non_sense]
142
- predicted += early_frameshifts if options[:frameshift]
94
+ end
143
95
 
144
- MutatedIsoform.setup(predicted, organism)
96
+ returns "Ensembl Gene ID"
97
+ task :all_affected_genes => :array do
98
+ set_info :organism, genotype.organism
99
+ genotype.genes.clean_annotations.flatten.uniq
145
100
  end
146
- end
147
101
 
148
- module GenomicMutation
149
- extend Entity
150
- self.annotation :name
151
- self.annotation :organism
102
+ dep :all_affected_genes
103
+ returns "Ensembl Gene ID"
104
+ task :long_genes => :array do
105
+ all_affected_genes = step(:all_affected_genes).load
106
+ long_genes = all_affected_genes.select{|gene|
107
+ length = gene.max_protein_length
108
+ length and length > 1000 or gene.name =~ /^PCDH/
109
+ }
152
110
 
153
- self.format = "Genomic Mutation"
111
+ set_info :organism, genotype.organism
112
+ long_genes.clean_annotations
113
+ end
154
114
 
155
- def self2genes
156
- Sequence.job(:genes_at_genomic_positions, name, :organism => organism, :positions => Array === self ? self : [self]).run
115
+ returns "Ensembl Gene ID"
116
+ task :mutations_in_exon_junctions => :array do
117
+ set_info :organism, genotype.organism
118
+ genotype.select{|mutation| mutation.in_exon_junction?}.clean_annotations
157
119
  end
158
120
 
159
- def genes
160
- Gene.setup(self2genes.values.flatten.uniq, "Ensembl Gene ID", organism)
121
+ returns "Ensembl Gene ID"
122
+ input :threshold, :float, "from 0 to 1", 0.5
123
+ task :with_damaged_isoforms => :array do |threshold|
124
+ set_info :organism, genotype.organism
125
+ mutated_isoform_damage = Misc.process_to_hash(genotype.mutated_isoforms.flatten.compact){|list| MutatedIsoform.setup(list, genotype.organism).damage_scores}
126
+ genotype.select{|mutation| if mutation.mutated_isoforms then mutated_isoform_damage.values_at(*mutation.mutated_isoforms.flatten.compact).select{|score| not score.nil? and score > threshold}.any? else false; end}.genes.flatten.uniq.clean_annotations
161
127
  end
162
128
 
163
- def self2mutated_isoforms
164
- Sequence.job(:mutated_isoforms_for_genomic_mutations, name, :organism => organism, :mutations => Array === self ? self : [self]).run
129
+ returns "Ensembl Gene ID"
130
+ task :truncated => :array do
131
+ set_info :organism, genotype.organism
132
+ MutatedIsoform.setup(genotype.mutated_isoforms.flatten.compact, "Hsa/jun2011").
133
+ select{|isoform_mutation| isoform_mutation.truncated }.
134
+ protein.gene.to("Ensembl Gene ID").uniq.clean_annotations
165
135
  end
166
136
 
167
- def mutated_isoforms
168
- MutatedIsoform.setup(self2mutated_isoforms.values.flatten, organism)
137
+ returns "Ensembl Gene ID"
138
+ task :affected_exon_junctions => :array do
139
+ set_info :organism, genotype.organism
140
+ genotype.select{|mutation| mutation.in_exon_junction?}.genes.flatten.clean_annotations
169
141
  end
170
142
 
171
- def damaging_mutations(options = {})
172
- damaged_isoforms = mutated_isoforms.damaged(options)
173
- damaging_mutations = self2mutated_isoforms.select{|mutation, values|
174
- mutated_isoforms = values["Mutated Isoform"]
175
- (damaged_isoforms & mutated_isoforms).any?
176
- }.collect{|mutation, mutated_isoforms| mutation.dup}
177
- GenomicMutation.setup(damaging_mutations, name + '.damaging', organism)
143
+ dep :with_damaged_isoforms, :truncated, :affected_exon_junctions
144
+ returns "Ensembl Gene ID"
145
+ task :damaged_genes => :array do
146
+ set_info :organism, genotype.organism
147
+
148
+ with_damaged_isoforms = step(:with_damaged_isoforms).load.clean_annotations
149
+ truncated = step(:truncated).load.clean_annotations
150
+ affected_exon_junctions = step(:affected_exon_junctions).load.clean_annotations
151
+
152
+ (with_damaged_isoforms + truncated + affected_exon_junctions).uniq
178
153
  end
179
154
 
180
- def mutations_at_genes(genes)
181
- genes = genes.to("Ensembl Gene ID").compact
182
- s2g = self.self2genes
183
- subset = s2g.select("Ensembl Gene ID" => genes).keys.collect{|e| e.dup}
184
- GenomicMutation.setup(subset, name + '.mutations_at_genes', organism)
155
+ %w(all_affected_genes damaged_genes truncated with_damaged_isoforms affected_exon_junctions long_genes recurrent_genes).each do |name|
156
+ define_method name do |*args|
157
+ @cache ||= {}
158
+ @cache[[name, args]] ||= self.job(name, self.jobname).run
159
+ end
185
160
  end
186
161
  end
162
+
@@ -0,0 +1,179 @@
1
+ require 'rbbt/entity'
2
+ require 'rbbt/workflow'
3
+ require 'rbbt/sources/organism'
4
+ require 'rbbt/mutation/mutation_assessor'
5
+ require 'rbbt/mutation/sift'
6
+ require 'rbbt/entity/protein'
7
+ require 'rbbt/entity/gene'
8
+ require 'nokogiri'
9
+
10
+ module MutatedIsoform
11
+ extend Entity
12
+ self.annotation :organism
13
+
14
+ self.format = "Mutated Isoform"
15
+
16
+ property :protein do
17
+ if Array === self
18
+ Protein.setup(self.collect{|mutation| mutation.split(":").first}, "Ensembl Protein ID", organism)
19
+ else
20
+ Protein.setup(self.split(":").first, "Ensembl Protein ID", organism)
21
+ end
22
+ end
23
+
24
+ property :change => :single2array do
25
+ self.split(":").last
26
+ end
27
+
28
+ property :position => :single2array do
29
+ if change.match(/[^\d](\d+)[^\d]/)
30
+ $1.to_i
31
+ else
32
+ nil
33
+ end
34
+ end
35
+
36
+ property :ensembl_protein_image_url => :single2array do
37
+ ensembl_url = if organism == "Hsa" then "www.ensembl.org" else "#{organism.sub(/.*\//,'')}.archive.ensembl.org" end
38
+ "http://#{ensembl_url}/Homo_sapiens/Component/Transcript/Web/TranslationImage?db=core;p=#{protein};_rmd=d2a8;export=svg"
39
+ end
40
+
41
+ property :marked_svg => :single2array do
42
+ svg = Open.read(protein.ensembl_protein_image_url)
43
+ seq_len = protein.sequence_length
44
+ position = self.position
45
+
46
+
47
+ doc = Nokogiri::XML(svg)
48
+ width = doc.css('svg').first.attr('width').to_f
49
+ height = doc.css('svg').first.attr('height').to_f
50
+ start = doc.css('rect.ac').first.attr('x').to_f
51
+
52
+ if width and height and start and seq_len and position
53
+ offset = (width - start)/seq_len * position + start
54
+ svg.sub(/<\/svg>/,"<rect x='#{offset}' y='1' width='1' height='#{height}' style='fill:rgb(255,0,0);opacity:0.5;stroke:none;'></svg>")
55
+ else
56
+ svg
57
+ end
58
+ end
59
+
60
+ ASTERISK = "*"[0]
61
+ CONSECUENCES = %w(UTR SYNONYMOUS NOSTOP MISS-SENSE INDEL FRAMESHIFT NONSENSE)
62
+ property :consecuence => :single2array do
63
+ prot, change = self.split(":")
64
+
65
+ case
66
+ when change =~ /UTR/
67
+ "UTR"
68
+ when (change[0] == ASTERISK and not change[0] == change[-1])
69
+ "NOSTOP"
70
+ when (change[-1] == ASTERISK and not change[0] == change[-1])
71
+ "NONSENSE"
72
+ when change =~ /Indel/
73
+ "INDEL"
74
+ when change =~ /FrameShift/
75
+ "FRAMESHIFT"
76
+ when change[0] == change[-1]
77
+ "SYNONYMOUS"
78
+ else
79
+ "MISS-SENSE"
80
+ end
81
+ end
82
+
83
+ property :truncated => :array2single do
84
+ @truncated ||= begin
85
+ protein2sequence_length = Misc.process_to_hash(self.protein.flatten){|list| list.sequence_length}
86
+ self.collect do |isoform_mutation|
87
+
88
+ next if isoform_mutation.consecuence != "FRAMESHIFT" and isoform_mutation.consecuence != "NONSENSE"
89
+ protein = isoform_mutation.protein
90
+ position = isoform_mutation.position
91
+ sequence_length = protein2sequence_length[protein]
92
+
93
+ case
94
+ when (sequence_length.nil? or position.nil?)
95
+ nil
96
+ when position < sequence_length.to_f * 0.7
97
+ true
98
+ else
99
+ false
100
+ end
101
+ end
102
+ end
103
+
104
+ end
105
+
106
+ property :damage_scores => :array2single do
107
+ @damage_scores ||= begin
108
+ sift_scores.zip(mutation_assessor_scores).collect{|p|
109
+ p = p.compact
110
+ if p.empty?
111
+ nil
112
+ else
113
+ p.inject(0.0){|acc, e| acc += e} / p.length
114
+ end
115
+ }
116
+ end
117
+ end
118
+
119
+ property :sift_scores => :array2single do
120
+ @sift_scores ||= begin
121
+ missense = self.select{|iso_mut| iso_mut.consecuence == "MISS-SENSE"}
122
+
123
+ values = SIFT.chunked_predict(missense).values_at(*self).collect{|v|
124
+ v.nil? ? nil : v["Prediction"]
125
+ }
126
+
127
+ range = {nil => nil,
128
+ "" => nil,
129
+ "TOLERATED" => 0,
130
+ "*DAMAGING" => 1,
131
+ "DAMAGING" => 1}
132
+
133
+ range.values_at *values
134
+ end
135
+ end
136
+
137
+ property :mutation_assessor_scores => :array2single do
138
+ @mutation_assesor_scores ||= begin
139
+ missense = self.select{|mutation| mutation.consecuence == "MISS-SENSE"}
140
+
141
+ correspondance = {}
142
+ list = missense.zip(missense.protein.to "UniProt/SwissProt ID").collect do |mutation, uniprot|
143
+ prot, change = mutation.split(":")
144
+ next if uniprot.nil?
145
+ uniprot_change = [uniprot, change]
146
+ correspondance[uniprot_change] ||= []
147
+ correspondance[uniprot_change] << mutation
148
+ uniprot_change
149
+ end.compact
150
+
151
+ #return TSV.setup({}, :key_field => "Mutated Isoform", :fields => ["Func. Impact"], :type => :list) if list.empty?
152
+ return [nil] * self.length if list.empty?
153
+
154
+ tsv = MutationAssessor.chunked_predict(list.sort_by{|p| p * "_"})
155
+
156
+ #return TSV.setup({}, :key_field => "Mutated Isoform", :fields => ["Func. Impact"], :type => :list) if tsv.nil? or tsv.empty?
157
+ return [nil] * self.length if tsv.empty?
158
+
159
+ new = TSV.setup({}, :key_field => "Mutated Isoform", :fields => ["Func. Impact"], :type => :list)
160
+
161
+ tsv.each do |key, values|
162
+ correspondance[key.split(" ")].each do |mutation|
163
+ new[mutation] = values["Func. Impact"]
164
+ end
165
+ end
166
+
167
+
168
+ range = {nil => nil,
169
+ "" => nil,
170
+ "neutral" => 0,
171
+ "low" => 0.3,
172
+ "medium" => 0.6,
173
+ "high" => 1}
174
+
175
+ range.values_at *new.values_at(*self)
176
+ end
177
+ end
178
+
179
+ end
@@ -0,0 +1,19 @@
1
+ require 'rbbt/entity'
2
+ require 'rbbt/sources/pubmed'
3
+
4
+ module PMID
5
+ extend Entity
6
+
7
+ self.format = "PMID"
8
+
9
+ property :title => :array2single do
10
+ @title ||= begin
11
+ PubMed.get_article(self).values_at(*self).collect{|article| article.nil? ? nil : article.title}
12
+ end
13
+ end
14
+
15
+ property :pubmed_url => :single2array do
16
+ "<a class='pmid' href='http://www.ncbi.nlm.nih.gov/pubmed/#{self}'>#{ self }</a>"
17
+ end
18
+ end
19
+
@@ -3,6 +3,7 @@ require 'rbbt/workflow'
3
3
  require 'rbbt/sources/organism'
4
4
  require 'rbbt/statistics/hypergeometric'
5
5
  require 'rbbt/network/paths'
6
+ require 'rbbt/entity/gene'
6
7
 
7
8
  Workflow.require_workflow "Translation"
8
9
 
@@ -14,17 +15,48 @@ module Protein
14
15
  self.annotation :format
15
16
  self.annotation :organism
16
17
 
17
- def gene
18
- Gene.setup(to("Ensembl Protein ID"), "Ensembl Protein ID", organism)
18
+ self.format = "Ensembl Protein ID"
19
+
20
+ def ensembl
21
+ to "Ensembl Protein ID"
22
+ end
23
+
24
+ property :ensembl_protein_image_url => :single2array do
25
+ ensembl_url = if organism == "Hsa" then "www.ensembl.org" else "#{organism.sub(/.*\//,'')}.archive.ensembl.org" end
26
+ "http://#{ensembl_url}/Homo_sapiens/Component/Transcript/Web/TranslationImage?db=core;p=#{ensembl};_rmd=d2a8;export=svg"
19
27
  end
20
28
 
21
- def to(new_format)
29
+ property :to! => :array2single do |new_format|
22
30
  return self if format == new_format
23
- if Array === self
24
- Protein.setup(Translation.job(:translate_protein, "", :organism => organism, :proteins => self, :format => new_format).exec, new_format, organism)
25
- else
26
- Protein.setup(Translation.job(:translate_protein, "", :organism => organism, :proteins => [self], :format => new_format).exec.first, new_format, organism)
27
- end
31
+ Protein.setup(Translation.job(:translate_protein, "", :organism => organism, :proteins => self, :format => new_format).exec, new_format, organism)
32
+ end
33
+
34
+ property :to => :array2single do |new_format|
35
+ return self if format == new_format
36
+ to!(new_format).collect!{|v| v.nil? ? nil : v.first}
37
+ end
38
+
39
+ property :gene do
40
+ Gene.setup(to("Ensembl Protein ID").clean_annotations, "Ensembl Protein ID", organism)
41
+ end
42
+
43
+ property :pfam => :array2single do
44
+ index = Organism.gene_pfam(organism).tsv :flat, :persist => true
45
+ index.unnamed = true
46
+ pfam = index.values_at(*self).flatten
47
+ Pfam.setup pfam
48
+ end
49
+
50
+ property :sequence => :array2single do
51
+ @protein_sequence ||= begin
52
+ protein_sequence = Organism.protein_sequence(organism).tsv :persist => true
53
+ protein_sequence.unnamed = true
54
+ protein_sequence.values_at(*self.ensembl)
55
+ end
56
+ end
57
+
58
+ property :sequence_length => :array2single do
59
+ sequence.collect{|seq| seq.nil? ? nil : seq.length}
28
60
  end
29
61
  end
30
62
 
@@ -6,9 +6,49 @@ require 'test/unit'
6
6
  require 'rbbt/entity/gene'
7
7
 
8
8
  class TestGene < Test::Unit::TestCase
9
+ CDK5 = Gene.setup("CDK5", "Associated Gene Name", "Hsa")
10
+ TP53 = Gene.setup("TP53", "Associated Gene Name", "Hsa")
11
+ TWO = Gene.setup(["CDK5", "TP53"], "Associated Gene Name", "Hsa")
12
+
9
13
  def test_to
10
14
  assert_equal "1020", Gene.setup("CDK5", "Associated Gene Name", "Hsa").to("Entrez Gene ID")
11
15
  end
16
+
17
+ def test_long_name
18
+ assert_equal "cyclin-dependent kinase 5", Gene.setup("CDK5", "Associated Gene Name", "Hsa").long_name
19
+ assert_equal ["cyclin-dependent kinase 5"], Gene.setup(["CDK5"], "Associated Gene Name", "Hsa").long_name
20
+
21
+ assert_match /tumor/, Gene.setup("TP53", "Associated Gene Name", "Hsa").description
22
+ end
23
+
24
+ def test_transcripts
25
+ assert CDK5.transcripts.length > 1
26
+ assert_equal "Hsa", CDK5.transcripts.organism
27
+ assert_equal "Hsa", CDK5.make_list.transcripts.first.organism
28
+ assert_equal "Hsa", CDK5.transcripts.make_list.organism
29
+ end
30
+
31
+ def test_proteins
32
+ assert CDK5.proteins.length > 1
33
+ end
34
+
35
+ def test_max_protein_length
36
+ assert CDK5.max_protein_length > 200
37
+ assert Array === TWO.max_protein_length
38
+ assert TWO.max_protein_length.first > 200
39
+ end
40
+
41
+ def test_max_transcript_length
42
+ assert CDK5.max_transcript_length > 200
43
+ assert Array === TWO.max_transcript_length
44
+ assert TWO.max_transcript_length.first > 200
45
+ end
46
+
47
+ def test_range
48
+ assert Range === CDK5.range
49
+ assert Range === CDK5.make_list.range.first
50
+ end
51
+
12
52
  end
13
53
 
14
54
 
@@ -0,0 +1,38 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ require 'test/unit'
4
+ require 'rbbt/util/tmpfile'
5
+ require 'test/unit'
6
+ require 'rbbt/entity/genomic_mutation'
7
+
8
+ class TestGenomicMutation < Test::Unit::TestCase
9
+ MUTATION = GenomicMutation.setup("10:124745844:A:158", "Test", "Hsa/jun2011")
10
+ SPLICING = GenomicMutation.setup("18:14787040:A", "Test", "Hsa/jun2011")
11
+ GENOTYPE = GenomicMutation.setup(Rbbt.data.genotype.list, "Test", "Hsa/jun2011")
12
+
13
+ def test_genes
14
+ assert GENOTYPE.genes.flatten.to("Associated Gene Name").include? "PSTK"
15
+ end
16
+
17
+ def test_consolidate
18
+ assert GENOTYPE.genes.consolidate.to("Associated Gene Name").include? "PSTK"
19
+ end
20
+
21
+ def test_mutated_isoforms
22
+ assert MUTATION.mutated_isoforms.length > 1
23
+ assert ["PSTK"], MUTATION.mutated_isoforms.protein.gene.to("Associated Gene Name").uniq
24
+ end
25
+
26
+ def test_exon_junction
27
+ assert(!(MUTATION.in_exon_junction?))
28
+ assert SPLICING.in_exon_junction?
29
+ end
30
+
31
+ def test_over_gene
32
+ assert MUTATION.over_gene? Gene.setup("PSTK", "Associated Gene Name", "Hsa/jun2011").ensembl
33
+ assert(!(SPLICING.over_gene? Gene.setup("PSTK", "Associated Gene Name", "Hsa/jun2011").ensembl))
34
+ end
35
+
36
+ end
37
+
38
+
@@ -0,0 +1,37 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ require 'test/unit'
4
+ require 'rbbt/util/tmpfile'
5
+ require 'test/unit'
6
+ require 'rbbt/entity/mutated_isoform'
7
+
8
+ class TestMutatedIsoform < Test::Unit::TestCase
9
+ MUTATION = MutatedIsoform.setup("ENSP00000275493:G719A", "Hsa/jun2011")
10
+
11
+ def test_protein
12
+ assert_equal "EGFR", MUTATION.protein.gene.to("Associated Gene Name")
13
+ end
14
+
15
+ def test_truncated
16
+
17
+ protein = Protein.setup(Gene.setup("CDK5", "Associated Gene Name", "Hsa/jun2011").to("Ensembl Protein ID"), "Ensembl Protein ID", "Hsa/jun2011")
18
+
19
+ change_position = (protein.sequence_length.to_f * 0.5).to_i
20
+ wildtype = protein.sequence[(change_position..change_position)]
21
+ mutation = "*"
22
+ new_mutation = wildtype << change_position.to_s << mutation
23
+ mutation = MutatedIsoform.setup([protein, new_mutation] * ":", "Hsa/jun2011")
24
+ assert mutation.truncated
25
+
26
+
27
+ change_position = (protein.sequence_length.to_f * 0.9).to_i
28
+ wildtype = protein.sequence[(change_position..change_position)]
29
+ mutation = "*"
30
+ new_mutation = wildtype << change_position.to_s << mutation
31
+ mutation = MutatedIsoform.setup([protein, new_mutation] * ":", "Hsa/jun2011")
32
+ assert !mutation.truncated
33
+ end
34
+
35
+ end
36
+
37
+
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../test_helper')
2
+
3
+ require 'test/unit'
4
+ require 'rbbt/util/tmpfile'
5
+ require 'test/unit'
6
+ require 'rbbt/entity/protein'
7
+
8
+ class TestProtein < Test::Unit::TestCase
9
+ PROTEIN = Protein.setup("ENSP00000275493", "Hsa/jun2011")
10
+ PROTEIN_ARRAY = Protein.setup(["ENSP00000275493"], "Hsa/jun2011")
11
+
12
+ def test_clean_annotations
13
+ assert Protein === PROTEIN
14
+ assert(!(Protein === PROTEIN.clean_annotations))
15
+ assert Gene === PROTEIN.gene
16
+ assert(!(Protein === PROTEIN.gene))
17
+ assert(PROTEIN_ARRAY.respond_to? :annotated_array_clean_each)
18
+ assert(!(PROTEIN_ARRAY.clean_annotations.respond_to? :annotated_array_clean_each))
19
+ end
20
+
21
+ def test_gene
22
+ assert_equal "EGFR", PROTEIN.gene.to("Associated Gene Name")
23
+ end
24
+
25
+ end
26
+
27
+
File without changes
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbt-entities
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
- - 0
8
7
  - 1
9
8
  - 0
10
- version: 0.1.0
9
+ - 0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Miguel Vazquez
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-03 00:00:00 +02:00
18
+ date: 2011-11-17 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -71,12 +71,20 @@ extra_rdoc_files:
71
71
  files:
72
72
  - LICENSE
73
73
  - lib/rbbt/entity.rb
74
+ - lib/rbbt/entity/cnv.rb
74
75
  - lib/rbbt/entity/gene.rb
76
+ - lib/rbbt/entity/genomic_mutation.rb
75
77
  - lib/rbbt/entity/genotype.rb
76
78
  - lib/rbbt/entity/misc.rb
79
+ - lib/rbbt/entity/mutated_isoform.rb
80
+ - lib/rbbt/entity/pmid.rb
77
81
  - lib/rbbt/entity/protein.rb
78
82
  - test/test_helper.rb
79
83
  - test/rbbt/entity/test_gene.rb
84
+ - test/rbbt/entity/test_genomic_mutation.rb
85
+ - test/rbbt/entity/test_mutated_isoform.rb
86
+ - test/rbbt/entity/test_protein.rb
87
+ - test/rbbt/test_entity.rb
80
88
  has_rdoc: true
81
89
  homepage: http://github.com/mikisvaz/rbbt-util
82
90
  licenses: []
@@ -114,3 +122,7 @@ summary: Entities for the Ruby Bioinformatics Toolkit (rbbt)
114
122
  test_files:
115
123
  - test/test_helper.rb
116
124
  - test/rbbt/entity/test_gene.rb
125
+ - test/rbbt/entity/test_genomic_mutation.rb
126
+ - test/rbbt/entity/test_mutated_isoform.rb
127
+ - test/rbbt/entity/test_protein.rb
128
+ - test/rbbt/test_entity.rb