rhetor 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3f2702dc837acf720a37f663d219b2c3b59a13dc
4
+ data.tar.gz: 5fa1338de3e9f990594c8fa411e5eb24cfe07569
5
+ SHA512:
6
+ metadata.gz: a93d30c92bbb94a8805bf01d310077512535388d5df106b7bf678c5e220687668db307a442a19e2678acd68f7a4ceedcf826fd1aaf3bb86ff872f21bd6ca1e5a
7
+ data.tar.gz: a6d0a3b06821db3a832098e9759d1b6366b9eb4253ed70992da035ab9ec9a0443865ed3926debe342aad061cb81504721942e5a05bd8ca7d7062a98be1ce7df0
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /.idea/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --warnings
3
+ --require spec_helper
@@ -0,0 +1,5 @@
1
+ require: rubocop-rspec
2
+ Style/Documentation:
3
+ Enabled: false
4
+ Style/AccessorMethodName:
5
+ Enabled: false
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.3"
4
+ - "2.2.0"
@@ -0,0 +1,19 @@
1
+ # Change log
2
+
3
+ ## master (unreleased)
4
+
5
+ ## 0.1.0 (2015-01-06)
6
+
7
+ ### New features
8
+
9
+ * You can provide a block for LexicalAnalyser#analyse method and it will be run with each of encountered tokens.
10
+ * Tokens have values instead of corresponding substrings. You can provide an evaluator for any rule. It is a block that will be called if the pattern is encountered. It should receive a matched substring and return the value of the corresponding token. If the evaluator is omitted, the value of the token will coincide with the matched substring.
11
+ * Tokens can be represented as a string via to_s method
12
+
13
+ ### Changes
14
+
15
+ * Update example in README.md
16
+
17
+ ### Bugs fixed
18
+
19
+ * Fix Rake task `test:coverage'
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem 'coveralls', require: false
7
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Egor Dubenetskiy
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,102 @@
1
+ # Rhetor
2
+
3
+ [![GitHub](https://img.shields.io/badge/github-edubenetskiy/rhetor-blue.svg)](https://github.com/edubenetskiy/rhetor)
4
+ [![RubyGems.org](https://img.shields.io/badge/gem-rhetor-blue.svg)](https://www.rubygems.org/gems/rhetor)
5
+ [![Documentation](https://img.shields.io/badge/docs-rdoc.info-blue.svg)](http://www.rubydoc.info/gems/rhetor/frames)
6
+ [![License](https://img.shields.io/packagist/l/doctrine/orm.svg)](#license)
7
+
8
+ [![Dependency Status](https://gemnasium.com/edubenetskiy/rhetor.svg)](https://gemnasium.com/edubenetskiy/rhetor)
9
+ [![Coverage Status](https://img.shields.io/coveralls/edubenetskiy/rhetor.svg)](https://coveralls.io/r/edubenetskiy/rhetor?branch=master)
10
+ [![Build Status](https://api.travis-ci.org/edubenetskiy/rhetor.svg?branch=master)](https://travis-ci.org/edubenetskiy/rhetor)
11
+ [![Code Climate](https://codeclimate.com/github/edubenetskiy/rhetor/badges/gpa.svg)](https://codeclimate.com/github/edubenetskiy/rhetor)
12
+ [![Gem Version](https://badge.fury.io/rb/rhetor.svg)](https://github.com/edubenetskiy/rhetor/releases)
13
+
14
+
15
+ Rhetor is yet another lexical analyser library written in pure Ruby
16
+ with no runtime dependencies. It is properly documented and easy-to-use.
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'rhetor'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install rhetor
33
+
34
+ ## Usage
35
+
36
+ ```ruby
37
+ # Define behaviour
38
+ lexer = Rhetor::LexicalAnalyser.new do
39
+ # Within this block you can define your own rules, your own patterns
40
+ # to recognize. You can call these methods out of this block
41
+ # like this: lexer.rule(...), it also works.
42
+ rule '+', :plus
43
+ rule '-', :minus
44
+ rule '*', :asterisk
45
+ rule '/', :solidus
46
+ rule '(', :left_parenthesis
47
+ rule ')', :right_parenthesis
48
+
49
+ # This rule will return tokens with floating-point values.
50
+ # Actually, you can make Rhetor to return tokens with any types of values,
51
+ # you only have to provide an evaluator - a block which receives a matched
52
+ # substring and returns the desired value. Like here:
53
+ rule(/[-+]?[0-9]*\.?[0-9]+/, :number) { |string| string.to_f }
54
+
55
+ # Here we make Rhetor to ignore whitespaces via the regular expression:
56
+ ignore(/\s+/)
57
+ # We could also do it with a string: ignore ' ',
58
+ # but regular expressions are more powerful.
59
+ end
60
+
61
+ # Analyse method returns an array of tokens. You can provide a block
62
+ # and it will be run for each of encountered tokens.
63
+ tokens = lexer.analyse('2 + 2 * 2 - (25 / (3 + 70 / 4))') do |token|
64
+ puts token
65
+ end
66
+ # It produces:
67
+ # (number: 2.0 [0,1])
68
+ # (plus: "+" [2,1])
69
+ # (number: 2.0 [4,1])
70
+ # (asterisk: "*" [6,1])
71
+ # (number: 2.0 [8,1])
72
+ # (minus: "-" [10,1])
73
+ # (left_parenthesis: "(" [12,1])
74
+ # (number: 25.0 [13,2])
75
+ # (solidus: "/" [16,1])
76
+ # (left_parenthesis: "(" [18,1])
77
+ # (number: 3.0 [19,1])
78
+ # (plus: "+" [21,1])
79
+ # (number: 70.0 [23,2])
80
+ # (solidus: "/" [26,1])
81
+ # (number: 4.0 [28,1])
82
+ # (right_parenthesis: ")" [29,1])
83
+ # (right_parenthesis: ")" [30,1])
84
+
85
+ # Now get information about any of the tokens:
86
+ token = tokens.first # => (number: 2.0 [0,1])
87
+ token.value # => 2.0
88
+ token.name # => :number
89
+ token.position # => 0
90
+ token.length # => 1
91
+ ```
92
+
93
+ ## Contributing
94
+
95
+ 1. Fork it (https://github.com/edubenetskiy/rhetor)
96
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
97
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
98
+ 4. Push to the branch (`git push origin my-new-feature`)
99
+ 5. Create a new Pull Request
100
+
101
+ ## License
102
+ Rhetor © 2015 by Egor Dubenetskiy. Rhetor is licensed under the MIT license. Please see LICENSE.txt for further details.
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'yard'
3
+ require 'rspec/core/rake_task'
4
+ require 'rubocop/rake_task'
5
+ require 'inch/rake'
6
+
7
+ Inch::Rake::Suggest.new
8
+ YARD::Rake::YardocTask.new
9
+ RuboCop::RakeTask.new
10
+ RSpec::Core::RakeTask.new('spec')
11
+
12
+ task default: %w(spec rubocop)
@@ -0,0 +1,6 @@
1
+ require 'rhetor/version'
2
+ require 'rhetor/lexical_analyser'
3
+
4
+ # The primary module of the gem
5
+ module Rhetor
6
+ end
@@ -0,0 +1,9 @@
1
+ module Rhetor
2
+ RhetorError = Class.new(StandardError)
3
+ UnmatchedString = Class.new(RhetorError)
4
+ InvalidRuleName = Class.new(RhetorError)
5
+ RuleAlreadyExists = Class.new(RhetorError)
6
+ InvalidPattern = Class.new(RhetorError)
7
+ InvalidString = Class.new(RhetorError)
8
+ NoStringLoaded = Class.new(RhetorError)
9
+ end
@@ -0,0 +1,158 @@
1
+ require 'rhetor/exceptions'
2
+ require 'rhetor/token'
3
+
4
+ module Rhetor
5
+ # LexicalAnalyser is a class that performs lexical analysis
6
+ # of strings using a set of predefined rules.
7
+ #
8
+ # @!attribute [r] string
9
+ # @return [String] the string being analyzed
10
+ # @!attribute [r] position
11
+ # @return [Integer] the current position of analyser
12
+ #
13
+ # @author Egor Dubenetskiy <edubenetskiy@ya.ru>
14
+ #
15
+ class LexicalAnalyser
16
+ attr_reader :string, :position
17
+
18
+ # Creates a new lexical analyser and evaluates the passed block within it
19
+ # @param block [Block] the block to be executed
20
+ # @example Creating a simple HQ9+ parser
21
+ # lexer = Rhetor::LexicalAnalyser.new {
22
+ # rule 'H', :hello_world
23
+ # rule 'Q', :quine
24
+ # rule '9', :ninety_nine_bottles
25
+ # rule '+', :increment
26
+ # ignore /\s+/
27
+ # }
28
+ # @return [void]
29
+ #
30
+ def initialize(&block)
31
+ @string_patterns = {}
32
+ @regexp_patterns = {}
33
+ @ignored = []
34
+ @used_names = []
35
+ @evaluator = {}
36
+ @string = nil
37
+ @position = nil
38
+ (block.arity == 1) ? block[self] : instance_eval(&block) if block_given?
39
+ end
40
+
41
+ # Makes the analyser to recognize some pattern
42
+ # @param pattern [String, Regexp] the pattern
43
+ # @param name [Symbol] the name of the rule
44
+ # @param evaluator [Proc,nil] a proc. This proc will be called
45
+ # if the pattern is encountered. It receives a matched substring
46
+ # and calculates the value of the corresponding token. If this
47
+ # argument is omitted, the value of the token will coincide
48
+ # with the matched substring.
49
+ # @raise [InvalidPattern] if the pattern is not valid
50
+ # @raise [InvalidRuleName] unless the name of the rule is a symbol
51
+ # @raise [RuleAlreadyExists] if the rule with the same name already exists
52
+ # @return [void]
53
+ #
54
+ def rule(pattern, name, &evaluator)
55
+ check_rule(pattern, name)
56
+ @used_names.push name
57
+ @evaluator[name] = evaluator
58
+ array_name = "@#{pattern.class.name.downcase}_patterns".intern
59
+ instance_variable_get(array_name)[name] = pattern
60
+ end
61
+
62
+ # Makes the analyser to ignore some pattern
63
+ # @param pattern [String, Regexp] the pattern to be ignored
64
+ # @return [void]
65
+ #
66
+ def ignore(pattern)
67
+ fail InvalidPattern unless [String, Regexp].include? pattern.class
68
+ @ignored.push pattern unless @ignored.include? pattern
69
+ end
70
+
71
+ # Initiates the analysis of the string
72
+ # @param string [String] the string to be analyzed
73
+ # @return [void]
74
+ #
75
+ def begin_analysis(string)
76
+ fail InvalidString unless string.is_a? String
77
+ @string = string
78
+ @position = 0
79
+ @size = string.size
80
+ end
81
+
82
+ # @return [Token] the next token found in the string
83
+ # @raise [NoStringLoaded] if no string is being analyzed
84
+ # @raise [UnmatchedString] if the analyser is unable to get the next token
85
+ #
86
+ def next_token
87
+ fail NoStringLoaded unless @string
88
+ @position = skip_ignored(@string, @position)
89
+ return EOF_TOKEN if @position >= @size
90
+ name, length = string_pattern(@string, @position)
91
+ name, length = regexp_pattern(@string, @position) if length == 0
92
+ fail UnmatchedString, "at position #{@position}" if length == 0
93
+ token = make_token(name, @position, length)
94
+ @position += length
95
+ token
96
+ end
97
+
98
+ # Analyzes the given string
99
+ # @param string [String] the string to be analyzed
100
+ # @yieldparam token [Token] every encountered token
101
+ # @return [Array<Token>] the array of encountered tokens
102
+ #
103
+ def analyse(string, &block)
104
+ begin_analysis(string)
105
+ tokens = []
106
+ loop do
107
+ last_token = next_token
108
+ (last_token == EOF_TOKEN) ? break : tokens << last_token
109
+ block.call(last_token) if block_given?
110
+ end
111
+ tokens
112
+ end
113
+
114
+ private
115
+
116
+ def make_token(name, position, size)
117
+ substring = @string[position, size]
118
+ value = @evaluator[name] ? @evaluator[name].call(substring) : substring
119
+ Rhetor::Token.new(value, name, position, size)
120
+ end
121
+
122
+ def check_rule(pattern, name)
123
+ fail InvalidPattern unless [String, Regexp].include? pattern.class
124
+ fail InvalidRuleName unless name.is_a? Symbol
125
+ fail RuleAlreadyExists if @used_names.include? name
126
+ end
127
+
128
+ def string_pattern(string, position)
129
+ results = @string_patterns.map do |name, pattern|
130
+ [name, matched_size(pattern, string, position)]
131
+ end
132
+ results.max_by(&:last) || [nil, 0]
133
+ end
134
+
135
+ def regexp_pattern(string, position)
136
+ results = @regexp_patterns.map do |name, pattern|
137
+ [name, matched_size(pattern, string, position)]
138
+ end
139
+ # results.max_by(&:last) || [nil, 0]
140
+ results.sort_by(&:last).find { |_name, size| size > 0 } || [nil, 0]
141
+ end
142
+
143
+ def skip_ignored(string, position)
144
+ skipped = @ignored.map { |p| matched_size(p, string, position) }.max
145
+ skipped ? position + skipped : position
146
+ end
147
+
148
+ def matched_size(pattern, string, position)
149
+ if pattern.is_a? String
150
+ (string[position, pattern.size] == pattern) ? pattern.size : 0
151
+ elsif pattern.is_a? Regexp
152
+ md = string.match(pattern, position)
153
+ return 0 unless md
154
+ md.begin(0) == position ? md[0].size : 0
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,18 @@
1
+ module Rhetor
2
+ # Token class represents tokens matched from the input.
3
+ #
4
+ # @attr_reader [Object] value the value of the token
5
+ # @attr_reader [Symbol] name the name of the matched rule
6
+ # @attr_reader [Integer] position the position of the matched substring
7
+ # @attr_reader [Integer] length the length of the matched substring
8
+ #
9
+ Token = Struct.new :value, :name, :position, :length do
10
+ def to_s
11
+ "(#{name}: #{value.inspect} [#{position},#{length}])"
12
+ end
13
+
14
+ alias_method :inspect, :to_s
15
+ end
16
+
17
+ EOF_TOKEN = Token.new(nil, nil, -1, nil)
18
+ end
@@ -0,0 +1,3 @@
1
+ module Rhetor
2
+ VERSION = '0.2.0'
3
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rhetor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rhetor'
8
+ spec.version = Rhetor::VERSION
9
+ spec.authors = ['Egor Dubenetskiy']
10
+ spec.email = ['edubenetskiy@ya.ru']
11
+ spec.summary = 'Rhetor is yet another lexical analyser written in Ruby'
12
+ spec.description = 'Rhetor is yet another lexical analyser library
13
+ written in pure Ruby with no runtime dependencies,
14
+ properly documented and easy-to-use.'
15
+ spec.homepage = 'https://github.com/edubenetskiy/rhetor/'
16
+ spec.license = 'MIT'
17
+ spec.required_ruby_version = '>= 1.9.3'
18
+
19
+ spec.files = `git ls-files -z`.split("\x0")
20
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
21
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
22
+ spec.require_paths = ['lib']
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.7'
25
+ spec.add_development_dependency 'rake', '~> 10.4'
26
+ spec.add_development_dependency 'simplecov', '~> 0.9'
27
+ spec.add_development_dependency 'rspec', '~> 3.1'
28
+ spec.add_development_dependency 'rubocop', '~> 0.28'
29
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.2'
30
+ spec.add_development_dependency 'inch', '~> 0.5'
31
+ spec.add_development_dependency 'yard', '~> 0.8'
32
+ end
@@ -0,0 +1,91 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rhetor do
4
+ describe LexicalAnalyser do
5
+ subject('analyser') do
6
+ described_class.new do |t|
7
+ t.rule 'key', :key
8
+ t.rule 'keyword', :keyword
9
+ t.rule 'word', :word
10
+ end
11
+ end
12
+
13
+ it 'returns an empty array being called with an empty string' do
14
+ expect(analyser.analyse '').to eq []
15
+ end
16
+
17
+ it 'returns an empty array if ignores anything' do
18
+ analyser.ignore(/.+/)
19
+ expect(analyser.analyse 'something anything').to eq []
20
+ end
21
+
22
+ it 'does not recognize an improper string' do
23
+ expect { analyser.analyse 'something' }.to raise_error(UnmatchedString)
24
+ end
25
+
26
+ it 'recognizes a single keyword' do
27
+ expect(analyser.analyse 'word').to eq [Token.new('word', :word, 0, 4)]
28
+ expect(analyser.analyse 'key').to eq [Token.new('key', :key, 0, 3)]
29
+ end
30
+
31
+ it 'recognizes a single pattern' do
32
+ analyser.rule(/\w+/, :custom_word)
33
+ expect(analyser.analyse 'something').to eq \
34
+ [Token.new('something', :custom_word, 0, 9)]
35
+ end
36
+
37
+ it 'recognizes a sequence of patterns and keywords' do
38
+ analyser.rule(/\w+/, :custom_word)
39
+ analyser.ignore(/\s+/)
40
+ expect(analyser.analyse 'some word').to eq \
41
+ [Token.new('some', :custom_word, 0, 4),
42
+ Token.new('word', :word, 5, 4)]
43
+ end
44
+
45
+ it 'takes only the longest token of several overlapped tokens' do
46
+ expect(analyser.analyse 'keyword').to eq \
47
+ [Token.new('keyword', :keyword, 0, 7)]
48
+ end
49
+
50
+ it 'recognizes several consecutive keywords' do
51
+ expect(analyser.analyse 'wordkeykeyword').to eq \
52
+ [Token.new('word', :word, 0, 4),
53
+ Token.new('key', :key, 4, 3),
54
+ Token.new('keyword', :keyword, 7, 7)]
55
+ end
56
+
57
+ it 'forbids the creation of rules with identical names' do
58
+ expect do
59
+ analyser.rule('key', :key)
60
+ end.to raise_error(RuleAlreadyExists)
61
+ end
62
+
63
+ it 'checks the validity of the names of the rules' do
64
+ expect do
65
+ analyser.rule('something', 'invalid rule name')
66
+ end.to raise_error(InvalidRuleName)
67
+ end
68
+
69
+ it 'checks the validity of the pattern' do
70
+ expect do
71
+ analyser.rule(:invalid_rule_pattern, :invalid_rule)
72
+ end.to raise_error(InvalidPattern)
73
+ end
74
+
75
+ it 'skips specified patterns' do
76
+ analyser.ignore(/\s+/)
77
+ expect(analyser.analyse 'word key keyword').to eq \
78
+ [Token.new('word', :word, 0, 4),
79
+ Token.new('key', :key, 5, 3),
80
+ Token.new('keyword', :keyword, 9, 7)]
81
+ end
82
+
83
+ it 'executes a passed block' do
84
+ expect do |b|
85
+ analyser.analyse('wordkeykeyword', &b)
86
+ end.to yield_successive_args(Token.new('word', :word, 0, 4),
87
+ Token.new('key', :key, 4, 3),
88
+ Token.new('keyword', :keyword, 7, 7))
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,7 @@
1
+ # Coverage support needs to be required *before* the Rhetor code is required!
2
+ require 'support/coverage'
3
+ require 'rhetor'
4
+ include Rhetor
5
+
6
+ RSpec.configure do |_config|
7
+ end
@@ -0,0 +1,11 @@
1
+ if ENV['TRAVIS'] || ENV['COVERAGE']
2
+ require 'simplecov'
3
+ if ENV['TRAVIS']
4
+ require 'coveralls'
5
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
6
+ end
7
+ SimpleCov.start do
8
+ add_filter '/spec/'
9
+ add_filter '/vendor/bundle/'
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Rhetor do
4
+ describe Token do
5
+ describe '#to_s' do
6
+ it 'returns a string representation of the token' do
7
+ expect(
8
+ Token.new('value', :name, 0, 42).to_s
9
+ ).to eq '(name: "value" [0,42])'
10
+ end
11
+ end
12
+ end
13
+ end
metadata ADDED
@@ -0,0 +1,182 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rhetor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Egor Dubenetskiy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-09-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.4'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.4'
41
+ - !ruby/object:Gem::Dependency
42
+ name: simplecov
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.9'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.9'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.28'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.28'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: inch
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.5'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.5'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.8'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.8'
125
+ description: |-
126
+ Rhetor is yet another lexical analyser library
127
+ written in pure Ruby with no runtime dependencies,
128
+ properly documented and easy-to-use.
129
+ email:
130
+ - edubenetskiy@ya.ru
131
+ executables: []
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - ".gitignore"
136
+ - ".rspec"
137
+ - ".rubocop.yml"
138
+ - ".travis.yml"
139
+ - CHANGELOG.md
140
+ - Gemfile
141
+ - LICENSE.txt
142
+ - README.md
143
+ - Rakefile
144
+ - lib/rhetor.rb
145
+ - lib/rhetor/exceptions.rb
146
+ - lib/rhetor/lexical_analyser.rb
147
+ - lib/rhetor/token.rb
148
+ - lib/rhetor/version.rb
149
+ - rhetor.gemspec
150
+ - spec/lexical_analyser_spec.rb
151
+ - spec/spec_helper.rb
152
+ - spec/support/coverage.rb
153
+ - spec/token_spec.rb
154
+ homepage: https://github.com/edubenetskiy/rhetor/
155
+ licenses:
156
+ - MIT
157
+ metadata: {}
158
+ post_install_message:
159
+ rdoc_options: []
160
+ require_paths:
161
+ - lib
162
+ required_ruby_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: 1.9.3
167
+ required_rubygems_version: !ruby/object:Gem::Requirement
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ version: '0'
172
+ requirements: []
173
+ rubyforge_project:
174
+ rubygems_version: 2.6.14
175
+ signing_key:
176
+ specification_version: 4
177
+ summary: Rhetor is yet another lexical analyser written in Ruby
178
+ test_files:
179
+ - spec/lexical_analyser_spec.rb
180
+ - spec/spec_helper.rb
181
+ - spec/support/coverage.rb
182
+ - spec/token_spec.rb