bel_parser 1.0.0.alpha.20 → 1.0.0.alpha.21

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: 5f5c683930e9f6671b818ec184fc5a8a35231984
4
- data.tar.gz: 04cb98ee13e3c6f57f2c9ea3a6b2188aba861918
3
+ metadata.gz: d6a168817ba0f0cede0a3b4c7fdd078514a8ee6f
4
+ data.tar.gz: 84bb8cded6070abe5f02e93703c149cbb3adfd88
5
5
  SHA512:
6
- metadata.gz: 362bc4fd38cb8cb60fcbf3c6a975671192258a9717101b53dd536e68e912d4af15f9c4620506f9782e2cefcab5fbf450586fc988a422e2710a1e8b6e273d41c1
7
- data.tar.gz: 6034289be41223dcda961ddafccc4079b62502ab3d4c8376eddee9bc7af109344cc16c2b442a9c4a6aac37186948f530875d3a7275da21bdc1408e5f1d8a5fa3
6
+ metadata.gz: b6960ba1eb867c53e98ea37be80617c7521773bd8676e348b1165a7ecf598acf9b6d005147423601b449c446638644cc130afec39856714b4ff70ac92b848f5e
7
+ data.tar.gz: 516482702677227cfdcb88aa44de29ea0a6ca3f00f1da74ad7e4ca3cfd6773d7df765e715b18e72a5e9a92845e05b1c5a2fdac1e52362d0a374073e75c24eff4
data/.gemspec CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  'Anthony Bargnesi',
12
12
  'Nick Bargnesi',
13
13
  ]
14
- spec.date = %q{2016-05-01}
14
+ spec.date = %q{2016-05-02}
15
15
  spec.email = %q{abargnesi@selventa.com}
16
16
  spec.files = [
17
17
  Dir.glob('lib/**/*.{rb,rl}'),
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.alpha.20
1
+ 1.0.0.alpha.21
@@ -0,0 +1,125 @@
1
+ require_relative 'evidence_serialization.rb'
2
+
3
+ # BEL Script evidence serialization that groups evidence by citation scoped to
4
+ # individual statement groups (i.e. BEL Script's +SET STATEMENT_GROUP+ and
5
+ # +UNSET STATEMENT_GROUP+).
6
+ #
7
+ # @example Citation serialization for a group of evidence
8
+ # SET STATEMENT_GROUP = 12857727
9
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
10
+ # SET Evidence = "USF1 and USF2 bound the IGF2R promoter in vitro, ..."
11
+ # SET CellLine = "MCF 10A"
12
+ # SET TextLocation = Abstract
13
+ # complex(p(HGNC:USF1),g(HGNC:IGF2R))
14
+ #
15
+ # complex(p(HGNC:USF2),g(HGNC:IGF2R))
16
+ #
17
+ # tscript(p(HGNC:USF2)) directlyIncreases r(HGNC:IGF2R)
18
+ #
19
+ # tscript(p(HGNC:USF1)) causesNoChange r(HGNC:IGF2R)
20
+ #
21
+ # SET Evidence = "c-Myc was present on the CDK4 promoter to the ..."
22
+ # complex(p(HGNC:MYC),g(HGNC:CDK4))
23
+ # UNSET STATEMENT_GROUP
24
+ module BEL::Translator::Plugins::BelScript::BelCitationSerialization
25
+ include BEL::Translator::Plugins::BelScript::EvidenceSerialization
26
+
27
+ # Serialize the {BEL::Model::Evidence evidence} to a BEL Script string.
28
+ #
29
+ # Includes +SET AnnotationName+ and +UNSET AnnotationName+ where needed in
30
+ # order to remove duplicating annotations.
31
+ #
32
+ # @param [BEL::Model::Evidence] evidence the evidence to serialize
33
+ # @return [String] the BEL Script string
34
+ def to_bel(evidence)
35
+ bel = ''
36
+
37
+ citation = citation_value(evidence)
38
+ summary_text = summary_text_value(evidence)
39
+ annotations = annotation_values(evidence)
40
+
41
+ current_annotations = {}.merge(annotations)
42
+ current_annotations[:Citation] = citation if citation
43
+ current_annotations[:Evidence] = summary_text if summary_text
44
+
45
+ if !evidence.citation.id || evidence.citation.id.empty?
46
+ citation_id = quote('')
47
+ else
48
+ citation_id = quote_if_needed(evidence.citation.id)
49
+ end
50
+
51
+ # Reset cumulative annotations if new citation.
52
+ if cumulative_citation == nil
53
+ bel << %Q{SET STATEMENT_GROUP = #{citation_id}\n}
54
+ cumulative_annotations.clear
55
+ elsif evidence.citation != cumulative_citation
56
+ bel << %Q{UNSET STATEMENT_GROUP\n}
57
+ bel << "\n\n"
58
+ bel << %Q{SET STATEMENT_GROUP = #{citation_id}\n}
59
+ cumulative_annotations.clear
60
+ end
61
+
62
+ # Hang on to the last citation.
63
+ self.cumulative_citation = evidence.citation
64
+
65
+ # UNSET unused annotations from previous evidence.
66
+ (cumulative_annotations.keys - current_annotations.keys).each do |unset_key|
67
+ bel << "UNSET #{unset_key}\n"
68
+ cumulative_annotations.delete(unset_key)
69
+ end
70
+
71
+ # Remove annotation if key/value was SET by a previous evidence.
72
+ Hash[
73
+ cumulative_annotations.to_a & current_annotations.to_a
74
+ ].each do |same_k, _|
75
+ current_annotations.delete(same_k)
76
+ end
77
+
78
+ # Retain the current evidence's annotation in cumulative set.
79
+ cumulative_annotations.merge!(current_annotations)
80
+
81
+ # SET Citation
82
+ citation = current_annotations.delete(:Citation)
83
+ if citation
84
+ bel << "SET Citation = {#{citation}}\n"
85
+ end
86
+
87
+ # SET Evidence
88
+ summary_text = current_annotations.delete(:Evidence)
89
+ if summary_text
90
+ bel << %Q{SET Evidence = "#{summary_text}"\n}
91
+ end
92
+
93
+ # SET new or modified annotations
94
+ current_annotations.sort.each do |(name, value)|
95
+ bel << "SET #{name} = #{value}\n"
96
+ end
97
+
98
+ # Assert BEL statement
99
+ bel << "#{evidence.bel_statement}\n"
100
+
101
+ # Separate evidence by new line.
102
+ bel << "\n"
103
+
104
+ bel
105
+ end
106
+
107
+ private
108
+
109
+ # The cumulative citation that is active for the current evidence. This is
110
+ # tracked in order to decide when to begin a new statement group.
111
+ attr_accessor :cumulative_citation
112
+
113
+ # Returns the cumulative +Hash+ of annotations. This *state* is used to keep
114
+ # track of the active, scoped annotations as evidence is serialized.
115
+ def cumulative_annotations
116
+ @cumulative_annotations ||= {}
117
+ end
118
+
119
+ # Return BEL Script syntax that should completes the BEL Script document.
120
+ # For Citation serialization we will always end with the unset of a
121
+ # statement group.
122
+ def epilogue
123
+ %Q{UNSET STATEMENT_GROUP\n}
124
+ end
125
+ end
@@ -0,0 +1,109 @@
1
+ require_relative 'evidence_serialization'
2
+
3
+ # BEL Script evidence serialization that writes each evidence with their full
4
+ # set of annotations (i.e. includes all `SET` and necessary `UNSET` records).
5
+ # This style is more readable because it groups all set annotations near the
6
+ # BEL statement.
7
+ #
8
+ # @example Discrete serialization for a group of evidence
9
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
10
+ # SET Evidence = "USF1 and USF2 bound the IGF2R promoter in vitro, ..."
11
+ # SET CellLine = "MCF 10A"
12
+ # SET TextLocation = Abstract
13
+ # complex(p(HGNC:USF1),g(HGNC:IGF2R))
14
+ #
15
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
16
+ # SET Evidence = "USF1 and USF2 bound the IGF2R promoter in vitro, ..."
17
+ # SET CellLine = "MCF 10A"
18
+ # SET TextLocation = Abstract
19
+ # complex(p(HGNC:USF2),g(HGNC:IGF2R))
20
+ #
21
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
22
+ # SET Evidence = "USF1 and USF2 bound the IGF2R promoter in vitro, ..."
23
+ # SET CellLine = "MCF 10A"
24
+ # SET TextLocation = Abstract
25
+ # tscript(p(HGNC:USF2)) directlyIncreases r(HGNC:IGF2R)
26
+ #
27
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
28
+ # SET Evidence = "USF1 and USF2 bound the IGF2R promoter in vitro, ..."
29
+ # SET CellLine = "MCF 10A"
30
+ # SET TextLocation = Abstract
31
+ # tscript(p(HGNC:USF1)) causesNoChange r(HGNC:IGF2R)
32
+ #
33
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
34
+ # SET Evidence = "c-Myc was present on the CDK4 promoter to the ..."
35
+ # SET CellLine = "MCF 10A"
36
+ # SET TextLocation = Abstract
37
+ # complex(p(HGNC:MYC),g(HGNC:CDK4))
38
+ #
39
+ # UNSET CellLine
40
+ module BEL::Translator::Plugins::BelScript::BelDiscreteSerialization
41
+ include BEL::Translator::Plugins::BelScript::EvidenceSerialization
42
+
43
+ # Serialize the {BEL::Model::Evidence evidence} to a BEL Script string.
44
+ # Includes all necessary +SET AnnotationName+ and +UNSET AnnotationName+
45
+ # records around the BEL statement.
46
+ #
47
+ # @param [BEL::Model::Evidence] evidence the evidence to serialize
48
+ # @return [String] the BEL Script string
49
+ def to_bel(evidence)
50
+ bel = ''
51
+
52
+ citation = citation_value(evidence)
53
+ summary_text = summary_text_value(evidence)
54
+ annotations = annotation_values(evidence)
55
+
56
+ current_annotations = {}.merge(annotations)
57
+ current_annotations[:Citation] = citation if citation
58
+ current_annotations[:Evidence] = summary_text if summary_text
59
+
60
+ # UNSET unused annotations from previous evidence.
61
+ (cumulative_annotations.keys - current_annotations.keys).each do |unset_key|
62
+ bel << "UNSET #{unset_key}\n"
63
+ cumulative_annotations.delete(unset_key)
64
+ end
65
+
66
+ # Retain the current evidence's annotation in cumulative set.
67
+ cumulative_annotations.merge!(current_annotations)
68
+
69
+ # SET Citation
70
+ citation = current_annotations.delete(:Citation)
71
+ if citation
72
+ bel << "SET Citation = {#{citation}}\n"
73
+ end
74
+
75
+ # SET Evidence
76
+ summary_text = current_annotations.delete(:Evidence)
77
+ if summary_text
78
+ bel << %Q{SET Evidence = "#{summary_text}"\n}
79
+ end
80
+
81
+ # SET new or modified annotations
82
+ current_annotations.sort.each do |(name, value)|
83
+ bel << "SET #{name} = #{value}\n"
84
+ end
85
+
86
+ # Assert BEL statement
87
+ bel << "#{evidence.bel_statement}\n"
88
+
89
+ # Separate evidence by new line.
90
+ bel << "\n"
91
+
92
+ bel
93
+ end
94
+
95
+ private
96
+
97
+ # Returns the cumulative +Hash+ of annotations. This *state* is used to keep
98
+ # track of the active, scoped annotations as evidence is serialized.
99
+ def cumulative_annotations
100
+ @cumulative_annotations ||= {}
101
+ end
102
+
103
+ # Return BEL Script syntax that completes the BEL Script document.
104
+ # The empty string is returned since no ending syntax is necessary when
105
+ # serializing each evidence discretely.
106
+ def epilogue
107
+ ""
108
+ end
109
+ end
@@ -0,0 +1,100 @@
1
+ require_relative 'evidence_serialization.rb'
2
+
3
+ # BEL Script evidence serialization that writes evidence sequentially while
4
+ # including only the necessary unsetting of annotations (i.e. BEL Script's
5
+ # +UNSET AnnotationName+ syntax).
6
+ #
7
+ # @example Top-down serialization for a group of evidence
8
+ # SET Citation = {"PubMed", "Journal...", "12857727", "2003-08-11", "", ""}
9
+ # SET Evidence = "USF1 and USF2 bound the IGF2R promoter in vitro, ..."
10
+ # SET CellLine = "MCF 10A"
11
+ # SET TextLocation = Abstract
12
+ # complex(p(HGNC:USF1),g(HGNC:IGF2R))
13
+ #
14
+ # complex(p(HGNC:USF2),g(HGNC:IGF2R))
15
+ #
16
+ # tscript(p(HGNC:USF2)) directlyIncreases r(HGNC:IGF2R)
17
+ #
18
+ # tscript(p(HGNC:USF1)) causesNoChange r(HGNC:IGF2R)
19
+ #
20
+ # SET Evidence = "c-Myc was present on the CDK4 promoter to the ..."
21
+ # complex(p(HGNC:MYC),g(HGNC:CDK4))
22
+ #
23
+ # UNSET CellLine
24
+ module BEL::Translator::Plugins::BelScript::BelTopDownSerialization
25
+ include BEL::Translator::Plugins::BelScript::EvidenceSerialization
26
+
27
+ # Serialize the {BEL::Model::Evidence evidence} to a BEL Script string.
28
+ # Includes all necessary +SET AnnotationName+ and +UNSET AnnotationName+
29
+ # records within the scope of a citation's statement group.
30
+ #
31
+ # @param [BEL::Model::Evidence] evidence the evidence to serialize
32
+ # @return [String] the BEL Script string
33
+ def to_bel(evidence)
34
+ bel = ''
35
+
36
+ citation = citation_value(evidence)
37
+ summary_text = summary_text_value(evidence)
38
+ annotations = annotation_values(evidence)
39
+
40
+ current_annotations = {}.merge(annotations)
41
+ current_annotations[:Citation] = citation if citation
42
+ current_annotations[:Evidence] = summary_text if summary_text
43
+
44
+ # UNSET unused annotations from previous evidence.
45
+ (cumulative_annotations.keys - current_annotations.keys).each do |unset_key|
46
+ bel << "UNSET #{unset_key}\n"
47
+ cumulative_annotations.delete(unset_key)
48
+ end
49
+
50
+ # Remove annotation if key/value was SET by a previous evidence.
51
+ Hash[
52
+ cumulative_annotations.to_a & current_annotations.to_a
53
+ ].each do |same_k, _|
54
+ current_annotations.delete(same_k)
55
+ end
56
+
57
+ # Retain the current evidence's annotation in cumulative set.
58
+ cumulative_annotations.merge!(current_annotations)
59
+
60
+ # SET Citation
61
+ citation = current_annotations.delete(:Citation)
62
+ if citation
63
+ bel << "SET Citation = {#{citation}}\n"
64
+ end
65
+
66
+ # SET Evidence
67
+ summary_text = current_annotations.delete(:Evidence)
68
+ if summary_text
69
+ bel << %Q{SET Evidence = "#{summary_text}"\n}
70
+ end
71
+
72
+ # SET new or modified annotations
73
+ current_annotations.sort.each do |(name, value)|
74
+ bel << "SET #{name} = #{value}\n"
75
+ end
76
+
77
+ # Assert BEL statement
78
+ bel << "#{evidence.bel_statement}\n"
79
+
80
+ # Separate evidence by new line.
81
+ bel << "\n"
82
+
83
+ bel
84
+ end
85
+
86
+ private
87
+
88
+ # Returns the cumulative +Hash+ of annotations. This *state* is used to keep
89
+ # track of the active, scoped annotations as evidence is serialized.
90
+ def cumulative_annotations
91
+ @cumulative_annotations ||= {}
92
+ end
93
+
94
+ # Return BEL Script syntax that completes the BEL Script document.
95
+ # The empty string is returned since no ending syntax is necessary when
96
+ # serializing in a top-down manner.
97
+ def epilogue
98
+ ""
99
+ end
100
+ end
@@ -0,0 +1,79 @@
1
+ require 'bel/quoting'
2
+
3
+ # Serializing of common {BEL::Model::Evidence evidence} components to BEL
4
+ # Script syntax.
5
+ #
6
+ # @abstract
7
+ module BEL::Translator::Plugins::BelScript::EvidenceSerialization
8
+ include BEL::Quoting
9
+
10
+ # Serialize the {BEL::Model::Evidence evidence} to a BEL Script string.
11
+ #
12
+ # @param [BEL::Model::Evidence] evidence the evidence to serialize
13
+ # @return [String] the BEL Script string
14
+ # @abstract Include and override {#to_bel} to implement serialization
15
+ # {BEL::Model::Evidence evidence} to BEL Script
16
+ def to_bel(evidence)
17
+ end
18
+
19
+ # Return BEL Script syntax that completes the BEL Script document.
20
+ #
21
+ # @abstract
22
+ def epilogue
23
+ raise NotImplementedError.new("#{self.class}#epilogue")
24
+ end
25
+
26
+ protected
27
+
28
+ def citation_value(evidence)
29
+ citation = evidence.citation
30
+
31
+ return nil unless citation && citation.valid?
32
+
33
+ values = citation.to_a
34
+ values.map! { |v|
35
+ v ||= ""
36
+ if v.respond_to?(:each)
37
+ %Q{"#{v.join('|')}"}
38
+ else
39
+ %Q{"#{v}"}
40
+ end
41
+ }
42
+ values.join(', ')
43
+ end
44
+
45
+ def summary_text_value(evidence)
46
+ summary_text = evidence.summary_text
47
+
48
+ return nil unless summary_text && summary_text.value
49
+
50
+ value = summary_text.value
51
+ value.gsub!("\n", "")
52
+ value.gsub!('"', %Q{\\"})
53
+ value
54
+ end
55
+
56
+ def annotation_values(evidence)
57
+ experiment_context = evidence.experiment_context
58
+
59
+ return {} unless experiment_context
60
+
61
+ Hash[
62
+ experiment_context.
63
+ sort_by { |obj| obj[:name].to_sym }.
64
+ map { |obj|
65
+ name = obj[:name].to_sym
66
+ value = obj[:value]
67
+
68
+ value_s =
69
+ if value.respond_to? :map
70
+ "{#{value.map { |v| quote(v) }.join(', ')}}"
71
+ else
72
+ quote(value)
73
+ end
74
+
75
+ [name, value_s]
76
+ }
77
+ ]
78
+ end
79
+ end
@@ -0,0 +1,34 @@
1
+ require 'bel_parser'
2
+ require 'bel_parser/resource/resource_url_reader'
3
+ require 'bel/evidence_model'
4
+
5
+ module BEL::Translator::Plugins
6
+ module BelScript
7
+ class Reader
8
+ include ::BELParser::Script
9
+
10
+ def initialize(io)
11
+ @io = io
12
+ @state = {
13
+ resource_reader: BELParser::Resource::ResourceURLReader.new(true),
14
+ specification: BELParser::Language.specification('2.0'),
15
+ namespace_definitions: {}
16
+ }
17
+ end
18
+
19
+ def each
20
+ if block_given?
21
+ NanopubMapper.new(
22
+ Validator.new(
23
+ StateAggregator.new(
24
+ FirstNode.new(Filter.new(BELParser::ASTGenerator.new(@io))),
25
+ @state))).each do |hash|
26
+ yield ::BEL::Model::Evidence.create(hash)
27
+ end
28
+ else
29
+ enum_for(:each)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1,6 +1,8 @@
1
1
  # Requires the "bel" gem.
2
2
  # This is for the BelScript translator intended to be plugged into bel.rb.
3
3
  require 'bel/translator'
4
+ require_relative 'reader'
5
+ require_relative 'writer'
4
6
 
5
7
  module BEL::Translator::Plugins
6
8
  module BelScript
@@ -10,25 +12,25 @@ module BEL::Translator::Plugins
10
12
  include ::BEL::Translator
11
13
 
12
14
  def read(data, options = {})
13
- # EvidenceYielder.new(data, options)
15
+ Reader.new(data)
14
16
  end
15
17
 
16
18
  def write(objects, writer = StringIO.new, options = {})
17
- # if block_given?
18
- # BelYielder.new(objects, options).each { |bel_part|
19
- # yield bel_part
20
- # }
21
- # else
22
- # if writer
23
- # BelYielder.new(objects, options).each { |bel_part|
24
- # writer << "#{bel_part}"
25
- # writer.flush
26
- # }
27
- # writer
28
- # else
29
- # BelYielder.new(objects, options)
30
- # end
31
- # end
19
+ if block_given?
20
+ Writer.new(objects, options).each { |bel_part|
21
+ yield bel_part
22
+ }
23
+ else
24
+ if writer
25
+ Writer.new(objects, options).each { |bel_part|
26
+ writer << "#{bel_part}"
27
+ writer.flush
28
+ }
29
+ writer
30
+ else
31
+ Writer.new(objects, options)
32
+ end
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -0,0 +1,180 @@
1
+ require_relative 'bel_citation_serialization'
2
+ require_relative 'bel_discrete_serialization'
3
+ require_relative 'bel_top_down_serialization'
4
+ require 'bel'
5
+
6
+ module BEL::Translator::Plugins
7
+
8
+ module BelScript
9
+
10
+ class Writer
11
+
12
+ # Create a {Writer} object that serializes {BEL::Model::Evidence} to
13
+ # BEL Script.
14
+ #
15
+ # @param [Enumerator<BEL::Model::Evidence>] data evidence data iterated
16
+ # using +each+
17
+ # @option options [Boolean] :write_header +true+ to write the BEL Script
18
+ # document header; +false+ to not write the BEL Script document
19
+ # header
20
+ # @option options [Symbol,Module] :serialization the serialization
21
+ # technique to use for evidence; a +Module+ type will be used as
22
+ # is; a +Symbol+ type will be mapped as
23
+ # +:discrete+ => {BelDiscreteSerialization},
24
+ # +:topdown+ => {BelTopDownSerialization},
25
+ # +:citation+ => {BelCitationSerialization}; otherwise the default
26
+ # of {BelCitationSerialization} is used
27
+ def initialize(data, options = {})
28
+ @data = data
29
+ @streaming = options.fetch(:streaming, false)
30
+ @write_header = options.fetch(:write_header, true)
31
+ @annotation_reference_map = options.fetch(:annotation_reference_map, nil)
32
+ @namespace_reference_map = options.fetch(:namespace_reference_map, nil)
33
+
34
+ # augment self with BEL serialization stategy.
35
+ serialization = options[:serialization]
36
+ serialization_module =
37
+ case serialization
38
+ when Module
39
+ serialization
40
+ when String, Symbol
41
+ serialization_refs = {
42
+ :discrete => BelDiscreteSerialization,
43
+ :topdown => BelTopDownSerialization,
44
+ :citation => BelCitationSerialization,
45
+ }
46
+ serialization_module = serialization_refs[serialization.to_sym]
47
+ unless serialization_module
48
+ raise %Q{No BEL serialization strategy for "#{serialization}"}
49
+ end
50
+ serialization_module
51
+ else
52
+ # Default to citation serialization.
53
+ BelCitationSerialization
54
+ end
55
+
56
+ self_eigenclass = (class << self; self; end)
57
+ self_eigenclass.send(:include, serialization_module)
58
+ end
59
+
60
+ def each
61
+ if block_given?
62
+ combiner =
63
+ if @streaming
64
+ BEL::Model::StreamingEvidenceCombiner.new(@data)
65
+ elsif @annotation_reference_map && @namespace_reference_map
66
+ BEL::Model::MapReferencesCombiner.new(
67
+ @data,
68
+ BEL::Model::HashMapReferences.new(
69
+ @annotation_reference_map,
70
+ @namespace_reference_map
71
+ )
72
+ )
73
+ else
74
+ BEL::Model::BufferingEvidenceCombiner.new(@data)
75
+ end
76
+
77
+ header_flag = true
78
+ combiner.each { |evidence|
79
+
80
+ # serialize evidence
81
+ bel = to_bel(evidence)
82
+
83
+ if @write_header && header_flag
84
+ yield document_header(evidence.metadata.document_header)
85
+ yield namespaces(combiner.namespace_references)
86
+ yield annotations(combiner.annotation_references)
87
+
88
+ yield <<-COMMENT.gsub(/^\s+/, '')
89
+ ###############################################
90
+ # Statements Section
91
+ COMMENT
92
+ header_flag = false
93
+ end
94
+
95
+ yield bel
96
+ }
97
+
98
+ yield epilogue
99
+ else
100
+ to_enum(:each)
101
+ end
102
+ end
103
+
104
+ private
105
+
106
+ def document_header(header)
107
+ return "" unless header
108
+
109
+ bel = <<-COMMENT.gsub(/^\s+/, '')
110
+ ###############################################
111
+ # Document Properties Section
112
+ COMMENT
113
+
114
+ header.each { |name, value|
115
+ name_s = name.to_s
116
+ value_s =
117
+ if value.respond_to?(:each)
118
+ value.join('|')
119
+ else
120
+ value.to_s
121
+ end
122
+
123
+ # handle casing for document properties (special case, contactinfo)
124
+ name_s = (name_s.downcase == 'contactinfo') ?
125
+ 'ContactInfo' :
126
+ name_s.capitalize
127
+
128
+ bel << %Q{SET DOCUMENT #{name_s} = "#{value_s}"\n}
129
+ }
130
+
131
+ bel << "\n"
132
+ bel
133
+ end
134
+
135
+ def annotations(annotation_references)
136
+ bel = <<-COMMENT.gsub(/^\s+/, '')
137
+ ###############################################
138
+ # Annotation Definitions Section
139
+ COMMENT
140
+
141
+ return bel unless annotation_references
142
+
143
+ annotation_references.reduce(bel) { |bel, ref|
144
+ keyword, type, domain = ref.values_at(:keyword, :type, :domain)
145
+ bel << "DEFINE ANNOTATION #{keyword} AS "
146
+
147
+ case type.to_sym
148
+ when :uri
149
+ bel << %Q{URL "#{domain}"\n}
150
+ when :pattern
151
+ regex = domain.respond_to?(:source) ? domain.source : domain
152
+ bel << %Q{PATTERN "#{regex}"\n}
153
+ when :list
154
+ bel << %Q|LIST {#{domain.inspect[1...-1]}}\n|
155
+ end
156
+ bel
157
+ }
158
+ bel << "\n"
159
+ bel
160
+ end
161
+
162
+ def namespaces(namespace_references)
163
+ bel = <<-COMMENT.gsub(/^\s+/, '')
164
+ ###############################################
165
+ # Namespace Definitions Section
166
+ COMMENT
167
+
168
+ return bel unless namespace_references
169
+
170
+ namespace_references.reduce(bel) { |bel, ref|
171
+ keyword, url = ref.values_at(:keyword, :uri)
172
+ bel << %Q{DEFINE NAMESPACE #{keyword} AS URL "#{url}"\n}
173
+ bel
174
+ }
175
+ bel << "\n"
176
+ bel
177
+ end
178
+ end
179
+ end
180
+ end
@@ -19,12 +19,16 @@ module BELParser
19
19
  class ResourceURLReader
20
20
  include Reader
21
21
 
22
+ # Class ivars for tracking open {GDBM} databases.
23
+ @dataset_file = nil
24
+ @resource_files = {}
25
+
22
26
  DEFAULT_RESOURCE_VALUE_DELIMITER = '|'
23
27
  private_constant :DEFAULT_RESOURCE_VALUE_DELIMITER
24
28
 
25
29
  def initialize(reuse_database_files = false)
26
30
  @resources = {}
27
- @datasets = ::GDBM.new(_temporary_datasets_file)
31
+ @datasets = ResourceURLReader.open_datasets_file
28
32
  @reuse = reuse_database_files
29
33
  end
30
34
 
@@ -67,15 +71,14 @@ module BELParser
67
71
  def create_resource(url, line_enum)
68
72
  delimiter = DEFAULT_RESOURCE_VALUE_DELIMITER
69
73
  dataset = @datasets[url]
70
- value_database_file = _temporary_database_file(url)
71
- values = ::GDBM.new(value_database_file)
74
+ values = ResourceURLReader.open_resource_file(url)
72
75
 
73
76
  if @reuse && dataset && values.size > 0
74
77
  warn(
75
78
  <<-MSG.gsub(/^ {14}/, '')
76
79
  Warning - Reusing value database.
77
80
  URL: #{url}
78
- File: #{value_database_file}
81
+ File: #{ResourceURLReader._temporary_resource_file(url)}
79
82
  MSG
80
83
  )
81
84
  return {
@@ -130,31 +133,41 @@ module BELParser
130
133
  end
131
134
  end
132
135
 
133
- private
134
-
135
- def _get(url, &block)
136
- Net::HTTP.start(url.host, url.port) do |http|
137
- http.request(Net::HTTP::Get.new(url)) do |response|
138
- return response.read_body
139
- end
140
- end
136
+ def self.open_datasets_file
137
+ @dataset_file ||= ::GDBM.new(_temporary_datasets_file)
141
138
  end
142
139
 
143
- def _hash_url(url)
144
- Base64.encode64(Digest::SHA1.digest(url)).delete("/=\n")
140
+ def self.open_resource_file(url)
141
+ @resource_files[url] ||= ::GDBM.new(_temporary_resource_file(url))
145
142
  end
146
143
 
147
- def _temporary_datasets_file
144
+ def self._temporary_datasets_file
148
145
  resource_directory = File.join(Dir.tmpdir, 'belresources')
149
146
  FileUtils.mkdir_p(resource_directory)
150
147
  File.join(resource_directory, 'datasets.gdbm')
151
148
  end
152
149
 
153
- def _temporary_database_file(url)
150
+ def self._temporary_resource_file(url)
154
151
  resource_directory = File.join(Dir.tmpdir, 'belresources')
155
152
  FileUtils.mkdir_p(resource_directory)
156
153
  File.join(resource_directory, "#{_hash_url(url)}.gdbm")
157
154
  end
155
+
156
+ def self._hash_url(url)
157
+ Base64.encode64(Digest::SHA1.digest(url)).delete("/=\n")
158
+ end
159
+ private_class_method :_hash_url
160
+
161
+ private
162
+
163
+ def _get(url, &block)
164
+ Net::HTTP.start(url.host, url.port) do |http|
165
+ http.request(Net::HTTP::Get.new(url)) do |response|
166
+ return response.read_body
167
+ end
168
+ end
169
+ end
170
+
158
171
  end
159
172
  end
160
173
  end
@@ -4,8 +4,22 @@ module BELParser
4
4
  BEL_VERSION_STRING = 'BELVersion'.freeze
5
5
  BEL_VERSION_REGEX = /\A#{BEL_VERSION_STRING}\Z/i
6
6
 
7
+ CITATION = 'Citation'.freeze
8
+ CITATION_REGEX = /\A#{CITATION}\Z/i
9
+
10
+ SUPPORT = 'Support'.freeze
11
+ SUPPORT_REGEX = /\A#{SUPPORT}\Z/i
12
+
7
13
  def is_bel_version?(string)
8
- string.to_s.strip =~ BEL_VERSION_REGEX
14
+ string =~ BEL_VERSION_REGEX
15
+ end
16
+
17
+ def is_citation?(string)
18
+ string =~ CITATION_REGEX
19
+ end
20
+
21
+ def is_support?(string)
22
+ string =~ SUPPORT_REGEX
9
23
  end
10
24
  end
11
25
  end
@@ -1,32 +1,93 @@
1
+ require 'bel_parser/quoting'
2
+ require_relative '../parsers/serializer'
3
+
1
4
  module BELParser
2
5
  module Script
3
- # NanopubMapper maps BEL Script AST nodes to an aggregated nanopub.
6
+ # NanopubMapper maps BEL Script AST nodes and state to aggregated
7
+ # nanopub hash objects.
4
8
  class NanopubMapper
9
+ include BELParser::Parsers
10
+ include BELParser::Quoting
11
+
5
12
  STATEMENT_TYPES = [
6
13
  :simple_statement,
7
14
  :nested_statement,
8
15
  :observed_term
9
16
  ]
10
17
 
18
+ DEFINITIONS = [:annotation_definitions, :namespace_definitions]
19
+
11
20
  def initialize(ast_enum)
12
21
  @ast_enum = ast_enum
13
22
  end
14
23
 
15
- def each
24
+ def each(&block)
16
25
  if block_given?
17
26
  @ast_enum.each do |(line_nunber, line, ast_node, state)|
18
27
  next unless STATEMENT_TYPES.include?(ast_node.type)
28
+ yield nanopub(ast_node, state, &block)
29
+ end
30
+ else
31
+ enum_for(:each)
32
+ end
33
+ end
34
+
35
+ def nanopub(ast_node, state, &block)
36
+ {
37
+ bel_statement: serialize(ast_node),
38
+ citation: citation(state[:citation]),
39
+ support: support(state[:support]),
40
+ experiment_context: experiment_context(state[:annotations]),
41
+ references: references(*state.values_at(*DEFINITIONS)),
42
+ metadata: nil
43
+ }
44
+ end
45
+
46
+ def citation(citation)
47
+ citation.each do |field, value|
48
+ citation[field] = unquote(value)
49
+ end
50
+ end
19
51
 
20
- # TODO Add StateFunction for capturing :citation.
21
- # TODO Add BELSerializer AST processor. Serialize ast_node.
22
- # TODO One time: Map annotation and namespace definitions.
52
+ def support(support)
53
+ unquote(support)
54
+ end
23
55
 
24
- # TODO Collect annotations.
56
+ def experiment_context(annotations)
57
+ (annotations || []).map do |name, value|
58
+ {
59
+ name: name,
60
+ value: value
61
+ }
62
+ end
63
+ end
25
64
 
26
- # TODO Combine into hash. Yield.
65
+ def references(anno_defs, ns_defs)
66
+ {
67
+ annotations: (anno_defs || []).map do |keyword, (type, domain)|
68
+ {
69
+ keyword: keyword,
70
+ type: type,
71
+ domain: domain_value(type, domain)
72
+ }
73
+ end,
74
+ namespaces: (ns_defs || []).map do |keyword, uri|
75
+ {
76
+ keyword: keyword,
77
+ uri: domain_value(:uri, uri)
78
+ }
27
79
  end
80
+ }
81
+ end
82
+
83
+ def domain_value(type, domain)
84
+ case type
85
+ when :uri
86
+ domain.identifier
87
+ when :list
88
+ domain
28
89
  else
29
- enum_for(:each)
90
+ domain.to_s
30
91
  end
31
92
  end
32
93
  end
@@ -38,7 +99,9 @@ if __FILE__ == $PROGRAM_NAME
38
99
  File.join(File.expand_path(File.dirname(__FILE__)), '..', '..', '..', 'lib'))
39
100
 
40
101
  require 'json'
102
+ require 'bel_parser'
41
103
  require 'bel_parser/language'
104
+ require 'bel_parser/parsers/serializer'
42
105
  require 'bel_parser/script'
43
106
  require 'bel_parser/resource/resource_url_reader'
44
107
  include BELParser::Script
@@ -58,11 +121,18 @@ if __FILE__ == $PROGRAM_NAME
58
121
  namespace_definitions: namespaces
59
122
  }
60
123
 
61
- NanopubMapper.new(
62
- Validator.new(
63
- StateAggregator.new(
64
- FirstNode.new(Filter.new(BELParser::ASTGenerator.new(File.open(ARGV.first)))),
65
- initial_state))).each do |nanopub|
66
- JSON.dump(nanopub)
67
- end
124
+ io =
125
+ if ARGV.first
126
+ File.open(ARGV.first)
127
+ else
128
+ $stdin
129
+ end
130
+
131
+ nanopubs =
132
+ NanopubMapper.new(
133
+ Validator.new(
134
+ StateAggregator.new(
135
+ FirstNode.new(Filter.new(BELParser::ASTGenerator.new(io))),
136
+ initial_state))).each.to_a
137
+ puts JSON.dump(nanopubs)
68
138
  end
@@ -53,7 +53,7 @@ module BELParser
53
53
  url = unquote(url_node.string.string_literal)
54
54
  dataset = script_context[:resource_reader].retrieve_resource(url)
55
55
  script_context[:annotation_definitions] ||= Concurrent::Hash.new
56
- script_context[:annotation_definitions][prefix] = [:url, dataset]
56
+ script_context[:annotation_definitions][prefix] = [:uri, dataset]
57
57
  end
58
58
  private_class_method :handle_url
59
59
  end
@@ -2,6 +2,7 @@ require 'bel_parser/language'
2
2
  require 'bel_parser/quoting'
3
3
  require 'bel_parser/parsers/ast/node'
4
4
  require 'concurrent/hash'
5
+ require_relative '../keywords'
5
6
  require_relative '../state_function'
6
7
 
7
8
  module BELParser
@@ -9,17 +10,24 @@ module BELParser
9
10
  module State
10
11
  class Set
11
12
  extend StateFunction
13
+ extend BELParser::Script::Keyword
12
14
  extend BELParser::Quoting
13
15
 
14
16
  TARGET_NODE = BELParser::Parsers::AST::Set
15
17
  LIST_NODE = BELParser::Parsers::AST::List
18
+ FIELDS = %w(type name id date authors comment)
16
19
 
17
20
  def self.consume(ast_node, script_context)
18
21
  return nil unless ast_node.is_a?(TARGET_NODE)
19
22
  name, value = ast_node.children
20
23
  name_string = name.identifier.string_literal
21
24
  value_node = ast_node.value.children[0]
22
- if value_node.is_a?(LIST_NODE)
25
+ case
26
+ when is_citation?(name_string)
27
+ handle_citation(value_node, script_context)
28
+ when is_support?(name_string)
29
+ handle_support(value_node, script_context)
30
+ when value_node.is_a?(LIST_NODE)
23
31
  value_node
24
32
  .list_items.map { |li| li.children[0].string_literal }
25
33
  .each do |string|
@@ -36,6 +44,22 @@ module BELParser
36
44
  end
37
45
  end
38
46
 
47
+ def self.handle_citation(value_node, script_context)
48
+ if value_node.is_a?(LIST_NODE)
49
+ script_context[:citation] =
50
+ Hash[
51
+ FIELDS.zip(
52
+ value_node
53
+ .list_items
54
+ .map { |li| li.children[0].string_literal })
55
+ ]
56
+ end
57
+ end
58
+
59
+ def self.handle_support(value_node, script_context)
60
+ script_context[:support] = value_node.string_literal
61
+ end
62
+
39
63
  def self.handle_annotation(name, value, script_context)
40
64
  # add to annotation state
41
65
  script_context[:annotations] ||= Concurrent::Hash.new
@@ -49,6 +73,7 @@ module BELParser
49
73
  # clear annotation state
50
74
  script_context[:annotations] ||= Concurrent::Hash.new
51
75
  script_context[:annotations].clear
76
+ script_context[:citation] = nil
52
77
  end
53
78
  private_class_method :handle_statement_group
54
79
  end
@@ -2,6 +2,7 @@ require 'bel_parser/language'
2
2
  require 'bel_parser/quoting'
3
3
  require 'bel_parser/parsers/ast/node'
4
4
  require 'concurrent/hash'
5
+ require_relative '../keywords'
5
6
  require_relative '../state_function'
6
7
 
7
8
  module BELParser
@@ -9,6 +10,7 @@ module BELParser
9
10
  module State
10
11
  class Unset
11
12
  extend StateFunction
13
+ extend BELParser::Script::Keyword
12
14
  extend BELParser::Quoting
13
15
 
14
16
  TARGET_NODE = BELParser::Parsers::AST::Unset
@@ -27,14 +29,15 @@ module BELParser
27
29
  def self.handle_annotation(name, script_context)
28
30
  script_context[:annotations] ||= Concurrent::Hash.new
29
31
  script_context[:annotations].delete(name)
32
+ script_context[:citation] = nil if is_citation?(name)
30
33
  end
31
34
  private_class_method :handle_annotation
32
35
 
33
36
  def self.handle_statement_group(script_context)
34
37
  script_context.delete(:statement_group)
35
-
36
38
  script_context[:annotations] ||= Concurrent::Hash.new
37
39
  script_context[:annotations].clear
40
+ script_context[:citation] = nil
38
41
  end
39
42
  private_class_method :handle_statement_group
40
43
  end
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.20
4
+ version: 1.0.0.alpha.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Bargnesi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-05-01 00:00:00.000000000 Z
12
+ date: 2016-05-02 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: Implements language versions 1.0 and 2.0.
15
15
  email: abargnesi@selventa.com
@@ -27,7 +27,13 @@ files:
27
27
  - bin/bel2_validator
28
28
  - bin/bel_script_reader
29
29
  - lib/bel/translator/plugins/bel_script.rb
30
+ - lib/bel/translator/plugins/bel_script/bel_citation_serialization.rb
31
+ - lib/bel/translator/plugins/bel_script/bel_discrete_serialization.rb
32
+ - lib/bel/translator/plugins/bel_script/bel_top_down_serialization.rb
33
+ - lib/bel/translator/plugins/bel_script/evidence_serialization.rb
34
+ - lib/bel/translator/plugins/bel_script/reader.rb
30
35
  - lib/bel/translator/plugins/bel_script/translator.rb
36
+ - lib/bel/translator/plugins/bel_script/writer.rb
31
37
  - lib/bel_parser.rb
32
38
  - lib/bel_parser/ast_filter.rb
33
39
  - lib/bel_parser/ast_generator.rb