sequitur 0.1.03 → 0.1.05

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,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)