sequitur 0.1.03 → 0.1.05

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Mzg2M2MwZDY5M2M1Zjc5MGZlOWI5MTMwM2ExNTc3YWZlMWI4MjliZA==
4
+ MjI4NGQ0MTJmZjkyYzVlZDg0MTA3MTExMDU1NGI2MzRiODcyMTg1ZA==
5
5
  data.tar.gz: !binary |-
6
- OTY4NzRlYjJmMGU1Nzc4ZDdiZmNkYWFiNzRmMWU3OThiMmExNDNkYg==
6
+ YWFjNTY5ZWJmZjI0YWIwZWE5ZjRkOTU3NzA2ZDMwZjBjYjFkMmE3Mg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- Y2M3Mjg1ZTFkYzEzNWI0YWYwMmIxMGIzZGE5ZjZmZmE4NmRjMDQ3NGE3Nzhl
10
- YTZiMjM1ZWM1OTRiODAwMmE0NDg0NWI1MzYyZGQ1Y2RiMTAzNWMwMzFjNzE1
11
- OGVkYmNlYzBmMjlhYmI3NDZkZTZjYWNjY2VkZTk2MzQxNWQ4OGY=
9
+ OWNlODIxNjAzMTlhYzhhZjA5NWY4NTJlYjkxNjY1ZjMwYjU4YzZkMDU5ZDJi
10
+ M2JlNjNlMGM4ZTNkY2FkZGM0Njc2NTNiYTIyM2Q0Y2YyNTk2MjU5YWFkOWEz
11
+ NTE0ZjM0NjQ2NDdjMjhkYzNkMGNkN2M1OWZlMmUzZWZiMWZkMjM=
12
12
  data.tar.gz: !binary |-
13
- MTNiNjhlYTNhNGU1NjY4ZTUwNzkzNWRiYzllMDA5MjczYmFhMzE3MDJiZDI3
14
- NWUzYzIyNTJlMDYzZTUxOWFmOTM0MzE3MDU3YTJiMTgzMTVkN2QyMGU5ZDFi
15
- MmU0ZTMxZjYwMzNkZjFmNGVhMGU4M2E1ZTQ5YTliMDg4NmNlZGQ=
13
+ YTk1MjgzMzcxYWUwNmI2NDY3MDc3YmU5NTYxMjJkOTljY2EzOGRhYjI4ZWUw
14
+ ZDA1ZTYzMWJjYmQwMmMyMjU0ZTJmNTIzZjZjMWY4NGZhNmE4MDE0MTVkODBk
15
+ NThmODRiMzM3MTk5NGE2MTExMGMyZGFhYTgxNDBlZGIwZGRmZDE=
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### 0.1.05 / 2014-09-28
2
+ * [CHANGE] File `README.md`: added badge from inch-ci.org (documentation quality).
3
+
4
+ ### 0.1.04 / 2014-09-28
5
+ * [CHANGE] All methods are now documented (YARD reports 100% coverage).
6
+
1
7
  ### 0.1.03 / 2014-09-21
2
8
  * [CHANGE] Class `Sequitur::SequiturGrammar` Code refactoring: cleaner and simpler implementation the algorithm.
3
9
  * [CHANGE] Class `Sequitur::Digram`. Added new method `repeating?` that tells whether digram members are the same.
data/README.md CHANGED
@@ -6,6 +6,7 @@ _Ruby gem implementing the Sequitur algorithm_
6
6
  [![Build Status](https://travis-ci.org/famished-tiger/Sequitur.svg?branch=master)](https://travis-ci.org/famished-tiger/Sequitur)
7
7
  [![Gem Version](https://badge.fury.io/rb/sequitur.svg)](http://badge.fury.io/rb/sequitur)
8
8
  [![Dependency Status](https://gemnasium.com/famished-tiger/Sequitur.png)](https://gemnasium.com/famished-tiger/Sequitur)
9
+ [![Inline docs](http://inch-ci.org/github/famished-tiger/Sequitur.svg?branch=master)](http://inch-ci.org/github/famished-tiger/Sequitur)
9
10
 
10
11
 
11
12
  ### What is the Sequitur algorithm? ###
data/lib/sequitur.rb CHANGED
@@ -10,12 +10,12 @@ require_relative './sequitur/formatter/base_text'
10
10
 
11
11
  module Sequitur
12
12
 
13
- # Convenience method. Builds a Sequitur-generated grammar based
14
- # on the sequence of input tokens
13
+ # Build a Sequitur-generated grammar based on the sequence of input tokens.
14
+ #
15
15
  # @param tokens [StringOrEnumerator] The input sequence of input tokens.
16
- # Can be a sequence of characters (i.e. a String) or an Enumerator
17
- # Tokens returned by enumerator should respond to the :hash message.
18
- # Returns a SequiturGrammar instance.
16
+ # Can be a sequence of characters (i.e. a String) or an Enumerator.
17
+ # Tokens returned by enumerator should respond to the :hash message.
18
+ # @return [SequiturGrammar] a grammar that encodes the input.
19
19
  def self.build_from(tokens)
20
20
  input_sequence = case tokens
21
21
  when String then tokens.chars
@@ -3,22 +3,22 @@
3
3
 
4
4
  module Sequitur # Module used as a namespace
5
5
  # The version number of the gem.
6
- Version = '0.1.03'
6
+ Version = '0.1.05'
7
7
 
8
8
  # Brief description of the gem.
9
9
  Description = 'Ruby implementation of the Sequitur algorithm'
10
10
 
11
11
  # Constant Sequitur::RootDir contains the absolute path of Sequitur's
12
- # root directory. Note: it also ends with a slash character.
12
+ # start directory. Note: it also ends with a slash character.
13
13
  unless defined?(RootDir)
14
14
  # The initialisation of constant RootDir is guarded in order
15
15
  # to avoid multiple initialisation (not allowed for constants)
16
16
 
17
- # The root folder of Sequitur.
17
+ # The start folder of Sequitur.
18
18
  RootDir = begin
19
19
  require 'pathname' # Load Pathname class from standard library
20
- rootdir = Pathname(__FILE__).dirname.parent.parent.expand_path
21
- rootdir.to_s + '/' # Append trailing slash character to it
20
+ startdir = Pathname(__FILE__).dirname.parent.parent.expand_path
21
+ startdir.to_s + '/' # Append trailing slash character to it
22
22
  end
23
23
  end
24
24
  end # module
@@ -3,24 +3,28 @@
3
3
  module Sequitur # Module for classes implementing the Sequitur algorithm
4
4
 
5
5
  # In linguistics, a digram is a sequence of two letters.
6
- # In Sequitur a digram is a sequence of two consecutive symbols that
7
- # appear in a grammar (production) rule. Each symbol in a digram
6
+ # In Sequitur, a digram is a sequence of two consecutive symbols that
7
+ # appear in a production rule. Each symbol in a digram
8
8
  # can be a terminal or not.
9
9
  class Digram
10
10
  # The sequence of two consecutive grammar symbols.
11
+ # The two symbols should respond to the :hash message.
11
12
  attr_reader(:symbols)
12
13
 
13
- # An unique Hash key of the digram
14
+ # An unique hash key of the digram
14
15
  attr_reader(:key)
15
16
 
16
17
  # The production in which the digram occurs
17
18
  attr_reader(:production)
18
19
 
19
20
  # Constructor.
21
+ # A digram represents a sequence of two symbols
22
+ # (that appears in a rhs of a production).
23
+ # Terminal symbols must respond to the :hash message.
20
24
  # @param symbol1 [StringOrSymbol] First element of the digram
21
25
  # @param symbol2 [StringOrSymbol] Second element of the digram
22
26
  # @param aProduction [Production] Production in which the RHS
23
- # the sequence symbol1 symbol2 appears.
27
+ # the sequence symbol1 symbol2 appears.
24
28
  def initialize(symbol1, symbol2, aProduction)
25
29
  @symbols = [symbol1, symbol2]
26
30
  @key = "#{symbol1.hash.to_s(16)}:#{symbol2.hash.to_s(16)}"
@@ -28,12 +32,15 @@ class Digram
28
32
  end
29
33
 
30
34
  # Equality testing.
31
- # Returns true when keys of both digrams are equal
35
+ # true iff keys of both digrams are equal, false otherwise
36
+ # @param other [Digram] another to compare with
37
+ # @return [true/false]
32
38
  def ==(other)
33
39
  return key == other.key
34
40
  end
35
41
 
36
- # Return true when the digram consists of twice the same symbols
42
+ # Does the digram consists of twice the same symbols?
43
+ # @return [true/false] true when symbols.first == symbols.last
37
44
  def repeating?()
38
45
  return symbols[0] == symbols[1]
39
46
  end
@@ -3,9 +3,17 @@ require_relative 'grammar_visitor'
3
3
 
4
4
  module Sequitur # Module for classes implementing the Sequitur algorithm
5
5
 
6
+ # A dynamic grammar is a context-free grammar that can be built incrementally.
7
+ # Formally, a grammar has:
8
+ # One start production
9
+ # Zero or more other productions
10
+ # Each production has a rhs that is a sequence of grammar symbols.
11
+ # Grammar symbols are categorized into
12
+ # -terminal symbols (i.e. String, Ruby Symbol,...)
13
+ # -non-terminal symbols (i.e. ProductionRef)
6
14
  class DynamicGrammar
7
- # Link to the root - start - production.
8
- attr_reader(:root)
15
+ # Link to the start production.
16
+ attr_reader(:start)
9
17
 
10
18
  # The set of production rules of the grammar
11
19
  attr_reader(:productions)
@@ -15,10 +23,10 @@ class DynamicGrammar
15
23
 
16
24
 
17
25
  # Constructor.
18
- # Build a grammar with one empty rule as start/root rule
26
+ # Build a grammar with one empty rule as start/start rule.
19
27
  def initialize()
20
- @root = Production.new
21
- @productions = [ root ]
28
+ @start = Production.new
29
+ @productions = [ start ]
22
30
  @trace = false
23
31
  end
24
32
 
@@ -26,6 +34,7 @@ class DynamicGrammar
26
34
 
27
35
  # Emit a text representation of the grammar.
28
36
  # Each production rule is emitted per line.
37
+ # @return [String]
29
38
  def to_string()
30
39
  rule_text = productions.map(&:to_string).join("\n")
31
40
  return rule_text
@@ -33,16 +42,18 @@ class DynamicGrammar
33
42
 
34
43
 
35
44
  # Add a given production to the grammar.
45
+ # @param aProduction [Production]
36
46
  def add_production(aProduction)
37
47
  # TODO: remove output
38
48
  puts "Adding #{aProduction.object_id}" if trace
39
49
  puts aProduction.to_string if trace
40
- check_rhs_of(aProduction) # TODO: configurable check
41
50
  productions << aProduction
42
51
  end
43
52
 
44
53
 
45
- # Remove a production from the grammar
54
+ # Remove a production with given index from the grammar
55
+ # @param anIndex [Fixnum]
56
+ # @return [Production] the production removed from the grammar.
46
57
  def remove_production(anIndex)
47
58
  puts "Before production removal #{productions[anIndex].object_id}" if trace
48
59
  puts to_string if trace
@@ -56,55 +67,38 @@ class DynamicGrammar
56
67
 
57
68
 
58
69
  # Add the given token to the grammar.
70
+ # Append the token to the rhs of the start/start rule.
71
+ # @param aToken [Object] input token to add
59
72
  def add_token(aToken)
60
- append_symbol_to(root, aToken)
73
+ append_symbol_to(start, aToken)
61
74
  end
62
75
 
63
- # Part of the 'visitee' role.
64
- # [aVisitor] a GrammarVisitor instance
76
+ # Part of the 'visitee' role in the Visitor design pattern.
77
+ # A visitee is expected to accept the visit from a visitor object
78
+ # @param aVisitor [GrammarVisitor] the visitor object
65
79
  def accept(aVisitor)
66
80
  aVisitor.start_visit_grammar(self)
81
+
82
+ # Let's proceed with the visit of productions
67
83
  productions.each { |prod| prod.accept(aVisitor) }
84
+
68
85
  aVisitor.end_visit_grammar(self)
69
86
  end
70
87
 
71
88
  # Factory method. Returns a visitor for this grammar.
89
+ # @return [GrammarVisitor]
72
90
  def visitor()
73
91
  return GrammarVisitor.new(self)
74
92
  end
75
93
 
76
94
  protected
77
-
95
+
96
+ # Append a given symbol to the rhs of passed production.
97
+ # @param aProduction [Production]
98
+ # @param aSymbol [Object]
78
99
  def append_symbol_to(aProduction, aSymbol)
79
100
  aProduction.append_symbol(aSymbol)
80
101
  end
81
-
82
-
83
- # Check that every production reference in rhs is
84
- # pointing to a production of the grammar
85
- def check_rhs_of(aProduction)
86
- aProduction.references.each do |symb|
87
- referenced_prod = symb.production
88
- next if productions.include?(referenced_prod)
89
-
90
- msg = "Production #{aProduction.object_id} refers to"
91
- msg << " production #{referenced_prod.object_id}"
92
- msg << ' that is not part of the grammar.'
93
- fail StandardError, msg
94
- end
95
- end
96
-
97
-
98
- # Visitor pattern.
99
- # A visitee is expected to accept the visit from a visitor object
100
- def accept(aVisitor)
101
- aVisitor.start_visit_grammar(self)
102
-
103
- # Let's proceed with the visit of productions
104
- productions.each { |a_prod| a_prod.accept(aVisitor) }
105
-
106
- aVisitor.end_visit_grammar(self)
107
- end
108
102
  end # class
109
103
 
110
104
  end # module
@@ -1,4 +1,6 @@
1
1
  module Sequitur
2
+
3
+ # Namespace dedicated to grammar formatters.
2
4
  module Formatter
3
5
 
4
6
  # Superclass for grammar formatters.
@@ -7,7 +9,8 @@ module Sequitur
7
9
  attr(:output)
8
10
 
9
11
  # Constructor.
10
- # [anIO] an output IO where the formatter's result will be placed.
12
+ # @param anIO [IO] an output IO where the formatter's result will
13
+ # be placed.
11
14
  def initialize(anIO)
12
15
  @output = anIO
13
16
  end
@@ -16,6 +19,7 @@ module Sequitur
16
19
 
17
20
  # Given a grammar or a grammar visitor, perform the visit
18
21
  # and render the visit events in the output stream.
22
+ # @param aGrmOrVisitor [DynamicGrammar or GrammarVisitor]
19
23
  def render(aGrmOrVisitor)
20
24
  if aGrmOrVisitor.kind_of?(GrammarVisitor)
21
25
  a_visitor = aGrmOrVisitor
@@ -2,60 +2,86 @@ require_relative 'base_formatter'
2
2
 
3
3
  module Sequitur
4
4
  module Formatter
5
-
5
+
6
6
  # A formatter class that can render a dynamic grammar in plain text.
7
- # Synopsis:
8
- # some_grammar = ... # Points to a DynamicGrammar-like object
9
- # Output the result to the standard console output
10
- # formatter = Sequitur::Formatter::BaseText.new(STDOUT)
11
- # Render the grammar (through a visitor)
12
- # formatter.run(some_grammar.visitor)
7
+ # @example
8
+ # some_grammar = ... # Points to a DynamicGrammar-like object
9
+ # # Output the result to the standard console output
10
+ # formatter = Sequitur::Formatter::BaseText.new(STDOUT)
11
+ # # Render the grammar (through a visitor)
12
+ # formatter.run(some_grammar.visitor)
13
13
  class BaseText < BaseFormatter
14
14
 
15
15
  # Constructor.
16
- # [anIO]
16
+ # @param anIO [IO] The output stream to which the rendered grammar
17
+ # is written.
17
18
  def initialize(anIO)
18
19
  super(anIO)
19
20
  @prod_lookup = {}
20
21
  end
21
22
 
22
23
  public
23
-
24
+
25
+ # Method called by a GrammarVisitor to which the formatter subscribed.
26
+ # Notification of a visit event: the visitor is about to visit a grammar
27
+ # @param aGrammar [DynamicGrammar-like object]
24
28
  def before_grammar(aGrammar)
25
29
  aGrammar.productions.each_with_index do |a_prod, index|
26
30
  prod_lookup[a_prod] = index
27
31
  end
28
32
  end
29
33
 
34
+ # Method called by a GrammarVisitor to which the formatter subscribed.
35
+ # Notification of a visit event: the visitor is about to visit
36
+ # a production
37
+ # @param aProduction [aProduction]
30
38
  def before_production(aProduction)
31
39
  p_name = prod_name(aProduction)
32
40
  output.print p_name
33
41
  end
34
42
 
43
+ # Method called by a GrammarVisitor to which the formatter subscribed.
44
+ # Notification of a visit event: the visitor is about to visit
45
+ # the rhs of a production
46
+ # @param _ [Array]
35
47
  def before_rhs(_)
36
48
  output.print ' :'
37
49
  end
38
50
 
51
+ # Method called by a GrammarVisitor to which the formatter subscribed.
52
+ # Notification of a visit event: the visitor is about to visit
53
+ # a terminal symbol from the rhs of a production
54
+ # @param aSymbol [Object]
39
55
  def before_terminal(aSymbol)
40
56
  output.print " #{aSymbol}"
41
57
  end
42
58
 
43
-
59
+ # Method called by a GrammarVisitor to which the formatter subscribed.
60
+ # Notification of a visit event: the visitor is about to visit
61
+ # a non-terminal (= an allusion to a production) in the rhs of a
62
+ # production
63
+ # @param aProduction [Production] a production occurring in the rhs
44
64
  def before_non_terminal(aProduction)
45
65
  p_name = prod_name(aProduction)
46
66
  output.print " #{p_name}"
47
67
  end
48
68
 
69
+ # Method called by a GrammarVisitor to which the formatter subscribed.
70
+ # Notification of a visit event: the visitor complete the visit
71
+ # of a production
49
72
  def after_production(_)
50
73
  output.print ".\n"
51
74
  end
52
75
 
53
76
  private
54
77
 
78
+ # Read accessor of the production lookup
55
79
  def prod_lookup()
56
80
  return @prod_lookup
57
81
  end
58
-
82
+
83
+ # Generate a name of a given production.
84
+ # @param aProduction [Production]
59
85
  def prod_name(aProduction)
60
86
  prod_index = prod_lookup[aProduction]
61
87
  name = (prod_index == 0) ? 'start' : "P#{prod_index}"
@@ -3,11 +3,22 @@ require_relative 'base_formatter'
3
3
 
4
4
  module Sequitur
5
5
  module Formatter
6
+
7
+ # A formatter class that can render the notification events
8
+ # from a grammar visitor
9
+ # @example
10
+ # some_grammar = ... # Points to a DynamicGrammar-like object
11
+ # # Output the result to the standard console output
12
+ # formatter = Sequitur::Formatter::Debug.new(STDOUT)
13
+ # # Render the visit notifications
14
+ # formatter.run(some_grammar.visitor)
6
15
  class Debug < BaseFormatter
16
+ # Current indentation level
7
17
  attr(:indentation)
8
18
 
9
19
  # Constructor.
10
- # [anIO]
20
+ # @param anIO [IO] The output stream to which the rendered grammar
21
+ # is written.
11
22
  def initialize(anIO)
12
23
  super(anIO)
13
24
  @indentation = 0
@@ -15,47 +26,85 @@ module Sequitur
15
26
 
16
27
  public
17
28
 
29
+ # Method called by a GrammarVisitor to which the formatter subscribed.
30
+ # Notification of a visit event: the visitor is about to visit a grammar
31
+ # @param _ [DynamicGrammar-like object]
18
32
  def before_grammar(_)
19
33
  output_event(__method__, indentation)
20
34
  indent
21
35
  end
22
36
 
37
+ # Method called by a GrammarVisitor to which the formatter subscribed.
38
+ # Notification of a visit event: the visitor is about to visit
39
+ # a production
40
+ # @param _ [aProduction]
23
41
  def before_production(_)
24
42
  output_event(__method__, indentation)
25
43
  indent
26
44
  end
27
45
 
46
+ # Method called by a GrammarVisitor to which the formatter subscribed.
47
+ # Notification of a visit event: the visitor is about to visit
48
+ # the rhs of a production
49
+ # @param _ [Array]
28
50
  def before_rhs(_)
29
51
  output_event(__method__, indentation)
30
52
  indent
31
53
  end
32
54
 
55
+ # Method called by a GrammarVisitor to which the formatter subscribed.
56
+ # Notification of a visit event: the visitor is about to visit
57
+ # a terminal symbol from the rhs of a production
58
+ # @param _ [Object]
33
59
  def before_terminal(_)
34
60
  output_event(__method__, indentation)
35
61
  end
36
62
 
63
+ # Method called by a GrammarVisitor to which the formatter subscribed.
64
+ # Notification of a visit event: the visitor completed the visit of
65
+ # a terminal symbol from the rhs of a production
66
+ # @param _ [Object]
37
67
  def after_terminal(_)
38
68
  output_event(__method__, indentation)
39
69
  end
40
70
 
71
+ # Method called by a GrammarVisitor to which the formatter subscribed.
72
+ # Notification of a visit event: the visitor is about to visit
73
+ # a non-terminal (= an allusion to a production) in the rhs of a
74
+ # production
75
+ # @param _ [Production] a production occurring in the rhs
41
76
  def before_non_terminal(_)
42
77
  output_event(__method__, indentation)
43
78
  end
44
79
 
80
+ # Method called by a GrammarVisitor to which the formatter subscribed.
81
+ # Notification of a visit event: the visitor completed the visit of
82
+ # a non-terminal symbol from the rhs of a production.
83
+ # @param _ [Object]
45
84
  def after_non_terminal(_)
46
85
  output_event(__method__, indentation)
47
86
  end
48
87
 
88
+ # Method called by a GrammarVisitor to which the formatter subscribed.
89
+ # Notification of a visit event: the visitor completed the visit of
90
+ # the rhs of a production
91
+ # @param _ [Array]
49
92
  def after_rhs(_)
50
93
  dedent
51
94
  output_event(__method__, indentation)
52
95
  end
53
96
 
97
+ # Method called by a GrammarVisitor to which the formatter subscribed.
98
+ # Notification of a visit event: the visitor completed the visit
99
+ # of a production
54
100
  def after_production(_)
55
101
  dedent
56
102
  output_event(__method__, indentation)
57
103
  end
58
104
 
105
+ # Method called by a GrammarVisitor to which the formatter subscribed.
106
+ # Notification of a visit event: the visitor completed the visit
107
+ # of a grammar
59
108
  def after_grammar(_)
60
109
  dedent
61
110
  output_event(__method__, indentation)