srl_ruby 0.3.2 → 0.3.3

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: 192758cce667147a6b7369cf6d575aa7fb22b627
4
- data.tar.gz: 3f851cdb8557bc8baba910ded6e4e0433851fa6a
3
+ metadata.gz: 5d359b7fdd648df4b9e77e0bf64266b3fec2d474
4
+ data.tar.gz: 7a8a1efb3f978b8f45b15c47c0b457a6109daf37
5
5
  SHA512:
6
- metadata.gz: d88c26d001764e3b224e9e6f2346791300624d348d825098bf1fedd658bcb3b66234c868144d83d6a8f6a02740dc36805cd765417af16f44ed6f4e6698ac647f
7
- data.tar.gz: ced3406cfd86aed12bb5ca64ec7917cb9f3fdcbf20b29027c993b6e1402d793b2a5d5b9907c4de75cc293e04148f037208d232b7e7ed373b11d1d958a7e4f025
6
+ metadata.gz: 20c7d24104afefa0371692ca2f0713916b9a6edbc1825c32bb77ff1c29760fa46bd04731ab88914f8dbd1d97f1cbd523f8b5e765d57ad0cf9ea7938110161c95
7
+ data.tar.gz: 9110435c0ae7bf089c167a46c81f6aabe91a7f9d52926843654972877aef2ccc1838c5a5218e8eac1f628cf95328f1f044a62b9d1fc4cfbcc6db49752b24b9ee
data/.rubocop.yml CHANGED
@@ -1,3 +1,31 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'exp/**/*'
4
+
1
5
  Layout/EndOfLine:
2
6
  Enabled: true
3
- EnforcedStyle: lf
7
+ EnforcedStyle: lf
8
+
9
+ Metrics/BlockLength:
10
+ Enabled: true
11
+ Max: 300
12
+
13
+ Metrics/MethodLength:
14
+ Enabled: true
15
+ Max: 30
16
+
17
+ Metrics/ModuleLength:
18
+ Enabled: true
19
+ Max: 500
20
+
21
+ Naming/ConstantName:
22
+ Enabled: false
23
+
24
+ Naming/VariableName:
25
+ Enabled: false
26
+
27
+ Style/CommentedKeyword:
28
+ Enabled: false
29
+
30
+ Style/RedundantReturn:
31
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## [0.3.3] - 2018-04-19
2
+ ### Changed
3
+ - Binary `srl_ruby` now accepts a SRL filename as command-line argument. Command-line documentation updated.
4
+
5
+ ### Fixed
6
+ - Method `Tokenizer#_next_token` failed to recognize single letter followed by a comma
7
+ - Binary `srl_ruby` now loads source files from correct filepath
8
+ - Module `SRL` is no more an ancestor of class `Multiplicity`.
9
+
10
+
1
11
  ## [0.3.2] - 2018-04-13
2
12
  ### Added
3
13
  - `Cucumber` feature files are now part of the gem.
data/Rakefile CHANGED
@@ -7,13 +7,12 @@ RSpec::Core::RakeTask.new do |spec|
7
7
  spec.pattern = 'spec/**/*_spec.rb'
8
8
  end
9
9
 
10
-
11
10
  Cucumber::Rake::Task.new do |_|
12
11
  end
13
12
 
14
13
  # Combine RSpec and Cucumber tests
15
14
  desc 'Run tests, with RSpec and Cucumber'
16
- task test: [:spec, :cucumber]
15
+ task test: %i[spec cucumber]
17
16
 
18
17
  # Default rake task
19
18
  task default: :test
data/bin/srl_ruby CHANGED
@@ -1,28 +1,51 @@
1
1
  #!/usr/bin/env ruby
2
- require_relative '../lib/srl_ruby/srl_ruby'
2
+ require_relative '../lib/srl_ruby'
3
3
 
4
+ my_name = File.basename(__FILE__)
5
+ my_version = SrlRuby::VERSION
6
+ puts "#{my_name} v. #{my_version}"
4
7
 
5
8
  # Parse the input expression in command-line
6
9
  if ARGV.empty?
7
- my_name = File.basename(__FILE__)
8
- msg = <<-END_MSG
9
- Simple Regex Language parser:
10
- - Parses a subset of the SRL language and displays the parse tree
11
-
12
- Command-line syntax:
13
- ruby #{my_name} "SRL expression"
14
- where:
15
- the SRL expression is enclosed between double quotes (")
16
-
17
- Examples:
18
- ruby #{my_name} "letter from a to f exactly 4 times"
19
- ruby #{my_name} "uppercase letter between 2 and 3 times"
20
- ruby #{my_name} "digit from 0 to 7 once or more"
21
- END_MSG
10
+ msg = <<-MSG
11
+ Simple Regex Language compiler:
12
+ - Parses an SRL expression and displays the corresponding Regexp literal
13
+
14
+ Command-line syntax (I):
15
+ ========================
16
+ #{my_name} "SRL expression"
17
+ where:
18
+ the SRL expression is enclosed between double quotes (")
19
+
20
+ Examples:
21
+ #{my_name} "letter from a to f exactly 4 times"
22
+ #{my_name} "uppercase letter between 2 and 3 times"
23
+ #{my_name} "digit from 0 to 7 once or more"
24
+
25
+ Command-line syntax (II):
26
+ ========================
27
+ #{my_name} -f filename
28
+ where:
29
+ the filename is a text file containing the SRL expression to compile
30
+
31
+ Examples:
32
+ #{my_name} -f hexadecimal.srl
33
+ MSG
22
34
  puts msg
23
35
  exit(1)
24
36
  end
25
- puts 'SRL input: ' + ARGV[0]
26
- puts 'Resulting Regexp: /' + SrlRuby.parse(ARGV[0]) + '/'
37
+
38
+
39
+ if ARGV[0] =~ /^--?fi?l?e?$/
40
+ srl_file = ARGV[1]
41
+ result = SrlRuby.load_file(srl_file)
42
+ else
43
+ srl_expr = ARGV[0]
44
+ puts 'SRL input: ' + srl_expr
45
+ result = SrlRuby.parse(srl_expr)
46
+ end
47
+
48
+ puts 'Resulting Regexp: /' + result.to_s + '/'
49
+
27
50
 
28
51
  # End of file
@@ -7,9 +7,9 @@ module Regex # This module is used as a namespace
7
7
  # Assumption: characters are ordered by codepoint
8
8
  class CharRange < PolyadicExpression
9
9
  # Constructor.
10
- # [thelowerBound]
10
+ # [thelowerBound]
11
11
  # A character that will be the lower bound value for the range.
12
- # [theUpperBound]
12
+ # [theUpperBound]
13
13
  # A character that will be the upper bound value for the range.
14
14
  # TODO: optimisation. Build a Character if lower bound == upper bound.
15
15
  def initialize(theLowerBound, theUpperBound)
@@ -1,91 +1,89 @@
1
1
  # File: Multiplicity.rb
2
2
 
3
- module SRL
4
- module Regex # This module is used as a namespace
5
- # The multiplicity specifies by how much a given expression can be repeated.
6
- class Multiplicity
7
- # The lowest acceptable repetition count
8
- attr_reader(:lower_bound)
3
+ module Regex # This module is used as a namespace
4
+ # The multiplicity specifies by how much a given expression can be repeated.
5
+ class Multiplicity
6
+ # The lowest acceptable repetition count
7
+ attr_reader(:lower_bound)
9
8
 
10
- # The highest possible repetition count
11
- attr_reader(:upper_bound)
9
+ # The highest possible repetition count
10
+ attr_reader(:upper_bound)
12
11
 
13
- # An indicator that specifies how to repeat (:greedy, :lazy, :possessive)
14
- attr_reader(:policy)
12
+ # An indicator that specifies how to repeat (:greedy, :lazy, :possessive)
13
+ attr_reader(:policy)
15
14
 
16
- # @param aLowerBound [Integer]
17
- # @param anUpperBound [Integer, Symbol] integer or :more symbol
18
- # @param aPolicy [Symbol] One of: (:greedy, :lazy, :possessive)
19
- def initialize(aLowerBound, anUpperBound, aPolicy)
20
- @lower_bound = valid_lower_bound(aLowerBound)
21
- @upper_bound = valid_upper_bound(anUpperBound)
22
- @policy = valid_policy(aPolicy)
23
- end
24
-
25
- # Purpose: Return the String representation of the multiplicity.
26
- def to_str()
27
- case upper_bound
28
- when :more
29
- case lower_bound
30
- when 0
31
- subresult = '*'
32
- when 1
33
- subresult = '+'
34
- else
35
- subresult = "{#{lower_bound},}"
36
- end
15
+ # @param aLowerBound [Integer]
16
+ # @param anUpperBound [Integer, Symbol] integer or :more symbol
17
+ # @param aPolicy [Symbol] One of: (:greedy, :lazy, :possessive)
18
+ def initialize(aLowerBound, anUpperBound, aPolicy)
19
+ @lower_bound = valid_lower_bound(aLowerBound)
20
+ @upper_bound = valid_upper_bound(anUpperBound)
21
+ @policy = valid_policy(aPolicy)
22
+ end
37
23
 
38
- when lower_bound
39
- subresult = "{#{lower_bound}}"
40
- else
41
- if [lower_bound, upper_bound] == [0, 1]
42
- subresult = '?'
24
+ # Purpose: Return the String representation of the multiplicity.
25
+ def to_str()
26
+ case upper_bound
27
+ when :more
28
+ case lower_bound
29
+ when 0
30
+ subresult = '*'
31
+ when 1
32
+ subresult = '+'
43
33
  else
44
- subresult = "{#{lower_bound},#{upper_bound}}"
45
- end
46
- end
34
+ subresult = "{#{lower_bound},}"
35
+ end
47
36
 
48
- suffix = case policy
49
- when :greedy
50
- ''
51
- when :lazy
52
- '?'
53
- when :possessive
54
- '+'
55
- end
37
+ when lower_bound
38
+ subresult = "{#{lower_bound}}"
39
+ else
40
+ if [lower_bound, upper_bound] == [0, 1]
41
+ subresult = '?'
42
+ else
43
+ subresult = "{#{lower_bound},#{upper_bound}}"
44
+ end
45
+ end
56
46
 
57
- return subresult + suffix
47
+ suffix = case policy
48
+ when :greedy
49
+ ''
50
+ when :lazy
51
+ '?'
52
+ when :possessive
53
+ '+'
58
54
  end
59
55
 
60
- private
56
+ return subresult + suffix
57
+ end
61
58
 
62
- # Validation method. Return the validated lower bound value
63
- def valid_lower_bound(aLowerBound)
64
- err_msg = "Invalid lower bound of repetition count #{aLowerBound}"
65
- raise StandardError, err_msg unless aLowerBound.kind_of?(Integer)
66
- return aLowerBound
67
- end
59
+ private
68
60
 
69
- # Validation method. Return the validated lower bound value
70
- def valid_upper_bound(anUpperBound)
71
- err_msg = "Invalid upper bound of repetition count #{anUpperBound}"
72
- unless anUpperBound.kind_of?(Integer) || (anUpperBound == :more)
73
- raise StandardError, err_msg
74
- end
61
+ # Validation method. Return the validated lower bound value
62
+ def valid_lower_bound(aLowerBound)
63
+ err_msg = "Invalid lower bound of repetition count #{aLowerBound}"
64
+ raise StandardError, err_msg unless aLowerBound.kind_of?(Integer)
65
+ return aLowerBound
66
+ end
75
67
 
76
- return anUpperBound
68
+ # Validation method. Return the validated lower bound value
69
+ def valid_upper_bound(anUpperBound)
70
+ err_msg = "Invalid upper bound of repetition count #{anUpperBound}"
71
+ unless anUpperBound.kind_of?(Integer) || (anUpperBound == :more)
72
+ raise StandardError, err_msg
77
73
  end
78
74
 
79
- # Validation method. Return the validated policy value.
80
- def valid_policy(aPolicy)
81
- err_msg = "Invalid repetition policy '#{aPolicy}'."
82
- valid_policies = %i[greedy lazy possessive]
83
- raise StandardError, err_msg unless valid_policies.include? aPolicy
75
+ return anUpperBound
76
+ end
84
77
 
85
- return aPolicy
86
- end
87
- end # class
88
- end # module
78
+ # Validation method. Return the validated policy value.
79
+ def valid_policy(aPolicy)
80
+ err_msg = "Invalid repetition policy '#{aPolicy}'."
81
+ valid_policies = %i[greedy lazy possessive]
82
+ raise StandardError, err_msg unless valid_policies.include? aPolicy
83
+
84
+ return aPolicy
85
+ end
86
+ end # class
89
87
  end # module
90
88
 
91
89
  # End of file
@@ -34,7 +34,7 @@ module SrlRuby
34
34
  end
35
35
 
36
36
  def multiplicity(lowerBound, upperBound)
37
- return SRL::Regex::Multiplicity.new(lowerBound, upperBound, :greedy)
37
+ return Regex::Multiplicity.new(lowerBound, upperBound, :greedy)
38
38
  end
39
39
 
40
40
  def string_literal(aString, to_escape = true)
@@ -6,11 +6,11 @@ module SrlRuby
6
6
  builder = Rley::Syntax::GrammarBuilder.new do
7
7
  # Separators...
8
8
  add_terminals('LPAREN', 'RPAREN', 'COMMA')
9
-
9
+
10
10
  # Literal values...
11
11
  add_terminals('DIGIT_LIT', 'INTEGER', 'LETTER_LIT', 'CHAR_CLASS')
12
12
  add_terminals('LITERALLY', 'STRING_LIT', 'IDENTIFIER')
13
-
13
+
14
14
  # Keywords...
15
15
  add_terminals('BEGIN', 'STARTS', 'WITH')
16
16
  add_terminals('MUST', 'END', 'RAW')
@@ -74,8 +74,8 @@ module SrlRuby
74
74
  rule('digit_range' => %w[digit_or_number FROM DIGIT_LIT TO DIGIT_LIT]).as 'digits_from_to'
75
75
  rule('character_class' => %w[ANY CHARACTER]).as 'any_character'
76
76
  rule('character_class' => %w[NO CHARACTER]).as 'no_character'
77
- rule('character_class' => 'digit_or_number').as 'digit'
78
- rule('character_class' => %w[NO DIGIT]).as 'non_digit'
77
+ rule('character_class' => 'digit_or_number').as 'digit'
78
+ rule('character_class' => %w[NO DIGIT]).as 'non_digit'
79
79
  rule('character_class' => 'WHITESPACE').as 'whitespace'
80
80
  rule('character_class' => %w[NO WHITESPACE]).as 'no_whitespace'
81
81
  rule('character_class' => 'ANYTHING').as 'anything'
@@ -123,5 +123,6 @@ module SrlRuby
123
123
  end
124
124
 
125
125
  # And now build the grammar and make it accessible via a global constant
126
+ # [Rley::Syntax::Grammar]
126
127
  Grammar = builder.grammar
127
128
  end # module
@@ -124,7 +124,7 @@ module SrlRuby
124
124
  elsif (lexeme = scanner.scan(/'(?:\\'|[^'])*'/)) # Single quotes literal?
125
125
  unquoted = lexeme.gsub(/(^')|('$)/, '')
126
126
  token = build_token('STRING_LIT', unquoted)
127
- elsif (lexeme = scanner.scan(/[a-zA-Z]((?=\s)|$)/))
127
+ elsif (lexeme = scanner.scan(/[a-zA-Z]((?=\s|,)|$)/))
128
128
  token = build_token('LETTER_LIT', lexeme)
129
129
  elsif (lexeme = scanner.scan(/[a-zA-Z_][a-zA-Z0-9_]+/))
130
130
  keyw = @@keywords[lexeme.upcase]
@@ -133,7 +133,7 @@ module SrlRuby
133
133
  elsif (lexeme = scanner.scan(/[^,"\s]{2,}/))
134
134
  token = build_token('CHAR_CLASS', lexeme)
135
135
  else # Unknown token
136
- erroneous = curr_ch.nil? ? '' : curr_ch
136
+ erroneous = curr_ch.nil? ? '' : scanner.scan(/./)
137
137
  sequel = scanner.scan(/.{1,20}/)
138
138
  erroneous += sequel unless sequel.nil?
139
139
  raise ScanError.new("Unknown token #{erroneous} on line #{lineno}")
@@ -1,3 +1,3 @@
1
1
  module SrlRuby
2
- VERSION = '0.3.2'.freeze
2
+ VERSION = '0.3.3'.freeze
3
3
  end
data/lib/srl_ruby.rb CHANGED
@@ -3,22 +3,29 @@ require_relative './srl_ruby/tokenizer'
3
3
  require_relative './srl_ruby/grammar'
4
4
  require_relative './srl_ruby/ast_builder'
5
5
 
6
- module SrlRuby # This module is used as a namespace
7
- # Load the SRL expression contained in filename.
8
- # Returns an equivalent Regexp object.
9
- # @param filename [String] file name to parse.
10
- # @return [Regexp]
6
+ module SrlRuby
7
+ # Compile the SRL expression in given filename into a Regexp object.
8
+ # @param filename [String] Name of SRL file to parse
9
+ # @return [Regexp] A regexp object equivalent to the SRL expression.
11
10
  def self.load_file(filename)
12
11
  source = nil
13
12
  File.open(filename, 'r') { |f| source = f.read }
14
13
  return source if source.nil? || source.empty?
15
-
14
+
16
15
  return parse(source)
17
16
  end
18
-
19
- # Parse the SRL expression into its Regexp equivalent.
20
- # @param source [String] the SRL source to parse and convert.
21
- # @return [Regexp]
17
+
18
+ # Compile the given SRL expression into its Regexp equivalent.
19
+ # @param source [String] SRL expression to parse
20
+ # @return [Regexp] A regexp object equivalent to the SRL expression.
21
+ # @example Matching a (signed) integer literal
22
+ # some_srl =<<-SRL
23
+ # begin with
24
+ # (one of "+-") optional,
25
+ # digit once or more,
26
+ # must end
27
+ # SRL
28
+ # regex = SrlRuby::API.parse(some_srl) # => regex == /^[+\-]?\d+$/
22
29
  def self.parse(source)
23
30
  # Create a Rley facade object
24
31
  engine = Rley::Engine.new { |cfg| cfg.diagnose = true }
@@ -42,8 +49,6 @@ module SrlRuby # This module is used as a namespace
42
49
 
43
50
  # Now output the regexp literal
44
51
  root = ast_ptree.root
45
- # puts root.to_str # TODO remove this line
46
- # pp root
47
52
  return Regexp.new(root.to_str)
48
53
  end
49
54
  end # module
@@ -37,9 +37,9 @@ module Acceptance
37
37
  self.srl = aSRLExpression.dup
38
38
  self.match_tests = []
39
39
  self.no_match_tests = []
40
- self.capture_tests = []
40
+ self.capture_tests = []
41
41
  end
42
- end
42
+ end
43
43
 
44
44
  MatchTest = Struct.new(:test_string)
45
45
  NoMatchTest = Struct.new(:test_string)
@@ -3,77 +3,75 @@
3
3
  require_relative '../spec_helper' # Use the RSpec test framework
4
4
  require_relative '../../lib/regex/multiplicity'
5
5
 
6
- module SRL
7
- # Reopen the module, in order to get rid of fully qualified names
8
- module Regex # This module is used as a namespace
9
- describe Multiplicity do
10
- context 'Creation & initialisation' do
11
- it 'should be created with 3 arguments' do
12
- # Valid cases: initialized with two integer values and a policy symbol
13
- %i[greedy lazy possessive].each do |aPolicy|
14
- expect { Multiplicity.new(0, 1, aPolicy) }.not_to raise_error
15
- end
16
-
17
- # Invalid case: initialized with invalid policy value
18
- err = StandardError
19
- msg = "Invalid repetition policy 'KO'."
20
- expect { Multiplicity.new(0, :more, 'KO') }.to raise_error(err, msg)
6
+ # Reopen the module, in order to get rid of fully qualified names
7
+ module Regex # This module is used as a namespace
8
+ describe Multiplicity do
9
+ context 'Creation & initialisation' do
10
+ it 'should be created with 3 arguments' do
11
+ # Valid cases: initialized with two integer values and a policy symbol
12
+ %i[greedy lazy possessive].each do |aPolicy|
13
+ expect { Multiplicity.new(0, 1, aPolicy) }.not_to raise_error
21
14
  end
15
+
16
+ # Invalid case: initialized with invalid policy value
17
+ err = StandardError
18
+ msg = "Invalid repetition policy 'KO'."
19
+ expect { Multiplicity.new(0, :more, 'KO') }.to raise_error(err, msg)
22
20
  end
21
+ end
23
22
 
24
- context 'Provided services' do
25
- it 'should know its text representation' do
26
- policy2text = { greedy: '', lazy: '?', possessive: '+' }
23
+ context 'Provided services' do
24
+ it 'should know its text representation' do
25
+ policy2text = { greedy: '', lazy: '?', possessive: '+' }
27
26
 
28
- # Case: zero or one
29
- policy2text.each_key do |aPolicy|
30
- multi = Multiplicity.new(0, 1, aPolicy)
31
- expect(multi.to_str).to eq("?#{policy2text[aPolicy]}")
32
- end
27
+ # Case: zero or one
28
+ policy2text.each_key do |aPolicy|
29
+ multi = Multiplicity.new(0, 1, aPolicy)
30
+ expect(multi.to_str).to eq("?#{policy2text[aPolicy]}")
31
+ end
33
32
 
34
- # Case: zero or more
35
- policy2text.each_key do |aPolicy|
36
- multi = Multiplicity.new(0, :more, aPolicy)
37
- expect(multi.to_str).to eq("*#{policy2text[aPolicy]}")
38
- end
33
+ # Case: zero or more
34
+ policy2text.each_key do |aPolicy|
35
+ multi = Multiplicity.new(0, :more, aPolicy)
36
+ expect(multi.to_str).to eq("*#{policy2text[aPolicy]}")
37
+ end
39
38
 
40
- # Case: one or more
41
- policy2text.each_key do |aPolicy|
42
- multi = Multiplicity.new(1, :more, aPolicy)
43
- expect(multi.to_str).to eq("+#{policy2text[aPolicy]}")
44
- end
39
+ # Case: one or more
40
+ policy2text.each_key do |aPolicy|
41
+ multi = Multiplicity.new(1, :more, aPolicy)
42
+ expect(multi.to_str).to eq("+#{policy2text[aPolicy]}")
43
+ end
45
44
 
46
- # Case: exactly m times
47
- policy2text.each_key do |aPolicy|
48
- samples = [1, 2, 5, 100]
49
- samples.each do |aCount|
50
- multi = Multiplicity.new(aCount, aCount, aPolicy)
51
- expect(multi.to_str).to eq("{#{aCount}}#{policy2text[aPolicy]}")
52
- end
45
+ # Case: exactly m times
46
+ policy2text.each_key do |aPolicy|
47
+ samples = [1, 2, 5, 100]
48
+ samples.each do |aCount|
49
+ multi = Multiplicity.new(aCount, aCount, aPolicy)
50
+ expect(multi.to_str).to eq("{#{aCount}}#{policy2text[aPolicy]}")
53
51
  end
52
+ end
54
53
 
55
- # Case: m, n times
56
- policy2text.each_key do |aPolicy|
57
- samples = [1, 2, 5, 100]
58
- samples.each do |aCount|
59
- upper = aCount + 1 + rand(20)
60
- multi = Multiplicity.new(aCount, upper, aPolicy)
61
- expectation = "{#{aCount},#{upper}}#{policy2text[aPolicy]}"
62
- expect(multi.to_str).to eq(expectation)
63
- end
54
+ # Case: m, n times
55
+ policy2text.each_key do |aPolicy|
56
+ samples = [1, 2, 5, 100]
57
+ samples.each do |aCount|
58
+ upper = aCount + 1 + rand(20)
59
+ multi = Multiplicity.new(aCount, upper, aPolicy)
60
+ expectation = "{#{aCount},#{upper}}#{policy2text[aPolicy]}"
61
+ expect(multi.to_str).to eq(expectation)
64
62
  end
63
+ end
65
64
 
66
- # Case: m or more
67
- policy2text.each_key do |aPolicy|
68
- samples = [2, 3, 5, 100]
69
- samples.each do |aCount|
70
- multi = Multiplicity.new(aCount, :more, aPolicy)
71
- expect(multi.to_str).to eq("{#{aCount},}#{policy2text[aPolicy]}")
72
- end
65
+ # Case: m or more
66
+ policy2text.each_key do |aPolicy|
67
+ samples = [2, 3, 5, 100]
68
+ samples.each do |aCount|
69
+ multi = Multiplicity.new(aCount, :more, aPolicy)
70
+ expect(multi.to_str).to eq("{#{aCount},}#{policy2text[aPolicy]}")
73
71
  end
74
72
  end
75
73
  end
76
74
  end
77
- end # module
75
+ end
78
76
  end # module
79
77
  # End of file
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,7 @@ require_relative '../lib/srl_ruby'
5
5
  RSpec.configure do |config|
6
6
  # Enable flags like --only-failures and --next-failure
7
7
  config.example_status_persistence_file_path = '.rspec_status'
8
-
8
+
9
9
  config.expect_with :rspec do |c|
10
10
  # Disable the `should` syntax...
11
11
  c.syntax = :expect
@@ -10,9 +10,9 @@ module SrlRuby
10
10
  expect(token.lexeme).to eq(lexeme)
11
11
  end
12
12
  end
13
-
14
- subject { Tokenizer.new('') }
15
-
13
+
14
+ subject { Tokenizer.new('') }
15
+
16
16
  context 'Initialization:' do
17
17
  it 'should be initialized with a text to tokenize and a grammar' do
18
18
  expect { Tokenizer.new('anything') }.not_to raise_error
@@ -31,7 +31,7 @@ module SrlRuby
31
31
  expect(token.terminal).to eq('COMMA')
32
32
  expect(token.lexeme).to eq(',')
33
33
  end
34
-
34
+
35
35
  it 'should tokenize keywords' do
36
36
  sample = 'between Exactly oncE optional TWICE'
37
37
  subject.scanner.string = sample
@@ -40,14 +40,14 @@ module SrlRuby
40
40
  expect(tok.terminal).to eq(tok.lexeme.upcase)
41
41
  end
42
42
  end
43
-
43
+
44
44
  it 'should tokenize integer values' do
45
45
  subject.scanner.string = ' 123 '
46
46
  token = subject.tokens.first
47
47
  expect(token).to be_kind_of(Rley::Lexical::Token)
48
48
  expect(token.terminal).to eq('INTEGER')
49
49
  expect(token.lexeme).to eq('123')
50
- end
50
+ end
51
51
 
52
52
  it 'should tokenize single digits' do
53
53
  subject.scanner.string = ' 1 '
@@ -55,9 +55,9 @@ module SrlRuby
55
55
  expect(token).to be_kind_of(Rley::Lexical::Token)
56
56
  expect(token.terminal).to eq('DIGIT_LIT')
57
57
  expect(token.lexeme).to eq('1')
58
- end
58
+ end
59
59
  end # context
60
-
60
+
61
61
  context 'String literal tokenization:' do
62
62
  it "should recognize 'literally ...'" do
63
63
  input = 'literally "hello"'
@@ -67,9 +67,9 @@ module SrlRuby
67
67
  %w[STRING_LIT hello]
68
68
  ]
69
69
  match_expectations(subject, expectations)
70
- end
71
- end # context
72
-
70
+ end
71
+ end # context
72
+
73
73
  context 'Character range tokenization:' do
74
74
  it "should recognize 'letter from ... to ...'" do
75
75
  input = 'letter a to f'
@@ -81,9 +81,9 @@ module SrlRuby
81
81
  %w[LETTER_LIT f]
82
82
  ]
83
83
  match_expectations(subject, expectations)
84
- end
84
+ end
85
85
  end # context
86
-
86
+
87
87
  context 'Quantifier tokenization:' do
88
88
  it "should recognize 'exactly ... times'" do
89
89
  input = 'exactly 4 Times'
@@ -95,7 +95,7 @@ module SrlRuby
95
95
  ]
96
96
  match_expectations(subject, expectations)
97
97
  end
98
-
98
+
99
99
  it "should recognize 'between ... and ... times'" do
100
100
  input = 'Between 2 AND 4 times'
101
101
  subject.scanner.string = input
@@ -129,7 +129,7 @@ module SrlRuby
129
129
  %w[MORE more]
130
130
  ]
131
131
  match_expectations(subject, expectations)
132
- end
132
+ end
133
133
 
134
134
  it "should recognize 'at least ... times'" do
135
135
  input = 'at least 10 times'
@@ -141,7 +141,7 @@ module SrlRuby
141
141
  %w[TIMES times]
142
142
  ]
143
143
  match_expectations(subject, expectations)
144
- end
144
+ end
145
145
  end # context
146
146
  end # describe
147
147
  end # module
@@ -44,7 +44,7 @@ describe SrlRuby do
44
44
  regexp = SrlRuby.parse("literally '.'")
45
45
  expect(regexp.source).to eq('\.')
46
46
  end
47
-
47
+
48
48
  it 'should parse single quotes literal string' do
49
49
  regexp = SrlRuby.parse('literally "an", whitespace, raw "[a-zA-Z]"')
50
50
  expect(regexp.source).to eq('an\s[a-zA-Z]')
@@ -61,7 +61,7 @@ describe SrlRuby do
61
61
  regexp = SrlRuby.parse('number')
62
62
  expect(regexp.source).to eq('\d')
63
63
  end
64
-
64
+
65
65
  it "should parse 'no digit' syntax" do
66
66
  regexp = SrlRuby.parse('no digit')
67
67
  expect(regexp.source).to eq('\D')
@@ -98,41 +98,41 @@ describe SrlRuby do
98
98
  # (escapes more characters than required)
99
99
  expect(regexp.source).to eq('[._%+\-]')
100
100
  end
101
-
101
+
102
102
  it "should parse 'one of' with unquoted character class syntax" do
103
103
  # Case of digit sequence
104
104
  regexp = SrlRuby.parse('one of 13579, must end')
105
105
  expect(regexp.source).to eq('[13579]$')
106
-
106
+
107
107
  # Case of identifier-like character class
108
108
  regexp = SrlRuby.parse('one of abcd, must end')
109
109
  expect(regexp.source).to eq('[abcd]$')
110
110
 
111
111
  # Case of arbitrary character class
112
112
  regexp = SrlRuby.parse('one of 12hms:, must end')
113
- expect(regexp.source).to eq('[12hms:]$')
114
- end
115
-
113
+ expect(regexp.source).to eq('[12hms:]$')
114
+ end
115
+
116
116
  it "should parse 'none of' syntax" do
117
117
  regexp = SrlRuby.parse('none of "._%+-"')
118
118
  # Remark: reference implementation less readable
119
119
  # (escapes more characters than required)
120
120
  expect(regexp.source).to eq('[^._%+\-]')
121
- end
121
+ end
122
122
 
123
123
  it "should parse 'none of' with unquoted character class syntax" do
124
124
  # Case of digit sequence
125
125
  regexp = SrlRuby.parse('none of 13579, must end')
126
126
  expect(regexp.source).to eq('[^13579]$')
127
-
127
+
128
128
  # Case of identifier-like character class
129
129
  regexp = SrlRuby.parse('none of abcd, must end')
130
130
  expect(regexp.source).to eq('[^abcd]$')
131
131
 
132
132
  # Case of arbitrary character class
133
133
  regexp = SrlRuby.parse('none of 12hms:^, must end')
134
- expect(regexp.source).to eq('[^12hms:\^]$')
135
- end
134
+ expect(regexp.source).to eq('[^12hms:\^]$')
135
+ end
136
136
  end # context
137
137
 
138
138
  context 'Parsing special character declarations:' do
@@ -140,7 +140,7 @@ describe SrlRuby do
140
140
  regexp = SrlRuby.parse('tab')
141
141
  expect(regexp.source).to eq('\t')
142
142
  end
143
-
143
+
144
144
  it "should parse 'vertical tab' syntax" do
145
145
  regexp = SrlRuby.parse('vertical tab')
146
146
  expect(regexp.source).to eq('\v')
@@ -155,21 +155,21 @@ describe SrlRuby do
155
155
  regexp = SrlRuby.parse('new line')
156
156
  expect(regexp.source).to eq('\n')
157
157
  end
158
-
158
+
159
159
  it "should parse 'carriage return' syntax" do
160
160
  regexp = SrlRuby.parse('carriage return')
161
161
  expect(regexp.source).to eq('\r')
162
- end
162
+ end
163
163
 
164
164
  it "should parse 'word' syntax" do
165
165
  regexp = SrlRuby.parse('word, literally "is"')
166
166
  expect(regexp.source).to eq('\bis')
167
- end
167
+ end
168
168
 
169
169
  it "should parse 'no word' syntax" do
170
170
  regexp = SrlRuby.parse('no word, literally "is"')
171
171
  expect(regexp.source).to eq('\Bis')
172
- end
172
+ end
173
173
  end # context
174
174
 
175
175
  context 'Parsing alternations:' do
@@ -177,25 +177,25 @@ describe SrlRuby do
177
177
  source = 'any of (any character, one of "._%-+")'
178
178
  regexp = SrlRuby.parse(source)
179
179
  expect(regexp.source).to eq('(?:\w|[._%\-+])')
180
- end
180
+ end
181
181
 
182
182
  it "should parse 'either of' syntax" do
183
183
  source = 'either of (any character, one of "._%-+")'
184
184
  regexp = SrlRuby.parse(source)
185
185
  expect(regexp.source).to eq('(?:\w|[._%\-+])')
186
- end
187
-
186
+ end
187
+
188
188
  it 'should anchor as alternative' do
189
189
  regexp = SrlRuby.parse('any of (literally "?", must end)')
190
190
  expect(regexp.source).to eq('(?:\\?|$)')
191
- end
191
+ end
192
192
  end # context
193
193
 
194
194
  context 'Parsing concatenation:' do
195
195
  it 'should reject dangling comma' do
196
196
  source = 'literally "a",'
197
197
  err = StandardError
198
- msg_pattern = /Premature end of input after ',' at position line 1, column 14/
198
+ msg_pattern = /Premature end of input after ',' at position line 1, column 14/
199
199
  expect { SrlRuby.parse(source) }.to raise_error(err, msg_pattern)
200
200
  end
201
201
 
@@ -205,13 +205,13 @@ describe SrlRuby do
205
205
  end
206
206
 
207
207
  it 'should parse a long sequence of patterns' do
208
- source = <<-END_SRL
208
+ source = <<-SRL
209
209
  any of (any character, one of "._%-+") once or more,
210
210
  literally "@",
211
211
  any of (digit, letter, one of ".-") once or more,
212
212
  literally ".",
213
213
  letter at least 2 times
214
- END_SRL
214
+ SRL
215
215
 
216
216
  regexp = SrlRuby.parse(source)
217
217
  # SRL: (?:\w|[\._%\-\+])+(?:@)(?:[0-9]|[a-z]|[\.\-])+(?:\.)[a-z]{2,}
@@ -246,9 +246,9 @@ END_SRL
246
246
  it "should parse 'between ... and ... times' syntax" do
247
247
  regexp = SrlRuby.parse(prefix + 'between 2 and 4 times')
248
248
  expect(regexp.source).to eq('[p-t]{2,4}')
249
-
249
+
250
250
  # Dropping 'times' keyword is a shorter alternative syntax
251
- regexp = SrlRuby.parse(prefix + 'between 2 and 4')
251
+ regexp = SrlRuby.parse(prefix + 'between 2 and 4')
252
252
  expect(regexp.source).to eq('[p-t]{2,4}')
253
253
  end
254
254
 
@@ -312,22 +312,22 @@ END_SRL
312
312
  regexp = SrlRuby.parse(source)
313
313
  expect(regexp.source).to eq('(?<first>.+)$')
314
314
  end
315
-
315
+
316
316
  it 'should parse complex named capturing group' do
317
- source = <<-END_SRL
318
- capture(any of (literally "sample", (digit once or more)))
317
+ source = <<-SRL
318
+ capture(any of (literally "sample", (digit once or more)))
319
319
  as "foo"
320
- END_SRL
320
+ SRL
321
321
  regexp = SrlRuby.parse(source)
322
322
  expect(regexp.source).to eq('(?<foo>(?:sample|(?:\d+)))')
323
323
  end
324
324
 
325
325
  it 'should parse a sequence with named capturing groups' do
326
- source = <<-END_SRL
326
+ source = <<-SRL
327
327
  capture (anything once or more) as "first",
328
328
  literally " - ",
329
329
  capture literally "second part" as "second"
330
- END_SRL
330
+ SRL
331
331
  regexp = SrlRuby.parse(source)
332
332
  expect(regexp.source).to eq('(?<first>.+) - (?<second>second part)')
333
333
  end
@@ -361,16 +361,16 @@ END_SRL
361
361
  end
362
362
 
363
363
  it 'should accept anchor with a sequence of patterns' do
364
- source = <<-END_SRL
364
+ source = <<-SRL
365
365
  begin with any of (digit, letter, one of ".-") once or more,
366
366
  literally ".",
367
367
  letter at least 2 times must end
368
- END_SRL
368
+ SRL
369
369
 
370
370
  regexp = SrlRuby.parse(source)
371
371
  # SRL: (?:\w|[\._%\-\+])+(?:@)(?:[0-9]|[a-z]|[\.\-])+(?:\.)[a-z]{2,}
372
372
  expect(regexp.source).to eq('^(?:\d|[a-z]|[.\-])+\.[a-z]{2,}$')
373
- end
373
+ end
374
374
  end # context
375
375
  end # describe
376
376
  # End of file
data/srl_ruby.gemspec CHANGED
@@ -1,8 +1,8 @@
1
-
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'srl_ruby/version'
5
4
 
5
+ # Implementation module
6
6
  module PkgExtending
7
7
  def self.pkg_files(aPackage)
8
8
  file_list = Dir[
@@ -42,29 +42,31 @@ Gem::Specification.new do |spec|
42
42
  spec.authors = ['Dimitri Geshef']
43
43
  spec.email = ['famished.tiger@yahoo.com']
44
44
 
45
- spec.description = %Q(Build easily regular expressions thanks to Simple Regex Language)
46
- spec.summary = <<-END_DESCR
47
- A parser for the [Simple Regex Language](https://simple-regex.com/).
48
- It translates patterns expressed in SRL into plain Ruby Regexp objects
49
- or in regex literals. Use self-documenting, human readable, SRL expressions
50
- to craft your new awesome regular expressions.
51
- END_DESCR
45
+ spec.description = <<-DESCR
46
+ Build easily regular expressions thanks to Simple Regex Language
47
+ DESCR
48
+ spec.summary = <<-SUMMARY
49
+ A parser for the [Simple Regex Language](https://simple-regex.com/).
50
+ It translates patterns expressed in SRL into plain Ruby Regexp objects
51
+ or in regex literals. Use self-documenting, human readable, SRL expressions
52
+ to craft your new awesome regular expressions.
53
+ SUMMARY
52
54
  spec.homepage = 'https://github.com/famished-tiger/SRL-Ruby'
53
55
  spec.license = 'MIT'
54
56
 
55
57
  spec.bindir = 'bin'
56
58
  spec.executables << 'srl_ruby'
57
59
  spec.require_paths = ['lib']
58
- PkgExtending::pkg_files(spec)
59
- PkgExtending::pkg_documentation(spec)
60
+ PkgExtending.pkg_files(spec)
61
+ PkgExtending.pkg_documentation(spec)
60
62
  spec.required_ruby_version = '>= 2.1.0'
61
-
63
+
62
64
  # Runtime dependencies
63
65
  spec.add_dependency 'rley', '~> 0.6.06'
64
66
 
65
67
  # Development dependencies
66
68
  spec.add_development_dependency 'bundler', '~> 1.16'
67
- spec.add_development_dependency 'cucumber', '>= 2.2.0'
69
+ spec.add_development_dependency 'cucumber', '>= 2.2.0'
68
70
  spec.add_development_dependency 'rake', '~> 10.0'
69
71
  spec.add_development_dependency 'rspec', '~> 3.0'
70
72
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: srl_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dimitri Geshef
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-04-13 00:00:00.000000000 Z
11
+ date: 2018-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rley
@@ -80,7 +80,8 @@ dependencies:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
82
  version: '3.0'
83
- description: Build easily regular expressions thanks to Simple Regex Language
83
+ description: |2
84
+ Build easily regular expressions thanks to Simple Regex Language
84
85
  email:
85
86
  - famished.tiger@yahoo.com
86
87
  executables:
@@ -202,9 +203,9 @@ rubygems_version: 2.6.13
202
203
  signing_key:
203
204
  specification_version: 4
204
205
  summary: A parser for the [Simple Regex Language](https://simple-regex.com/). It translates
205
- patterns expressed in SRL into plain Ruby Regexp objects or in regex literals.
206
- Use self-documenting, human readable, SRL expressions to craft your new awesome
207
- regular expressions.
206
+ patterns expressed in SRL into plain Ruby Regexp objects or in regex literals. Use
207
+ self-documenting, human readable, SRL expressions to craft your new awesome regular
208
+ expressions.
208
209
  test_files:
209
210
  - spec/acceptance/srl_test_suite_spec.rb
210
211
  - spec/regex/character_spec.rb