srl_ruby 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
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