fdlint 0.1.3 → 0.2.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -9
  3. data/Gemfile.lock +14 -4
  4. data/Rakefile +9 -85
  5. data/bin/fdlint +71 -8
  6. data/lib/fdlint/cli.rb +102 -0
  7. data/lib/{file_validator.rb → fdlint/file_validator.rb} +0 -0
  8. data/lib/fdlint/helper/code_type.rb +55 -0
  9. data/lib/fdlint/helper/file_reader.rb +19 -0
  10. data/lib/fdlint/helper/logger.rb +35 -0
  11. data/lib/fdlint/log_entry.rb +51 -0
  12. data/lib/fdlint/parser/base_parser.rb +151 -0
  13. data/lib/{css/parser.rb → fdlint/parser/css/css_parser.rb} +31 -28
  14. data/lib/{css → fdlint/parser/css}/struct.rb +5 -5
  15. data/lib/{encoding_error.rb → fdlint/parser/encoding_error.rb} +2 -2
  16. data/lib/{html/parser.rb → fdlint/parser/html/html_parser.rb} +26 -20
  17. data/lib/{html → fdlint/parser/html}/query.rb +0 -0
  18. data/lib/{html → fdlint/parser/html}/rule/check_tag_rule.rb +0 -0
  19. data/lib/{html → fdlint/parser/html}/struct.rb +82 -38
  20. data/lib/fdlint/parser/js/expr/expr.rb +71 -0
  21. data/lib/fdlint/parser/js/expr/left_hand.rb +65 -0
  22. data/lib/fdlint/parser/js/expr/operate.rb +94 -0
  23. data/lib/fdlint/parser/js/expr/primary.rb +168 -0
  24. data/lib/{js/parser.rb → fdlint/parser/js/js_parser.rb} +11 -9
  25. data/lib/fdlint/parser/js/stat/if.rb +27 -0
  26. data/lib/fdlint/parser/js/stat/iter.rb +88 -0
  27. data/lib/fdlint/parser/js/stat/stat.rb +120 -0
  28. data/lib/fdlint/parser/js/stat/switch.rb +67 -0
  29. data/lib/fdlint/parser/js/stat/try.rb +30 -0
  30. data/lib/fdlint/parser/js/stat/var.rb +42 -0
  31. data/lib/fdlint/parser/js/struct.rb +257 -0
  32. data/lib/fdlint/parser/node.rb +27 -0
  33. data/lib/fdlint/parser/parse_error.rb +10 -0
  34. data/lib/fdlint/parser/parser_visitable.rb +134 -0
  35. data/lib/{position_info.rb → fdlint/parser/position_info.rb} +12 -1
  36. data/lib/fdlint/parser.rb +3 -0
  37. data/lib/fdlint/printer/base_printer.rb +20 -0
  38. data/lib/fdlint/printer/console_printer.rb +80 -0
  39. data/lib/fdlint/printer/nocolor_printer.rb +29 -0
  40. data/lib/fdlint/printer/vim_printer.rb +21 -0
  41. data/lib/fdlint/printer.rb +1 -0
  42. data/lib/fdlint/rule/dsl.rb +83 -0
  43. data/lib/fdlint/rule/validation.rb +79 -0
  44. data/lib/fdlint/rule.rb +81 -0
  45. data/lib/fdlint/support/core/array.rb +5 -0
  46. data/lib/fdlint/support/core/file.rb +8 -0
  47. data/lib/fdlint/support/core/hash.rb +5 -0
  48. data/lib/fdlint/support/core/nil.rb +7 -0
  49. data/lib/fdlint/support/core/string.rb +7 -0
  50. data/lib/fdlint/support/core_ext.rb +5 -0
  51. data/lib/fdlint/validator.rb +102 -0
  52. data/lib/fdlint/version.rb +3 -0
  53. data/lib/fdlint.rb +5 -0
  54. data/rules.d/css.rule.rb +100 -0
  55. data/rules.d/filename.rule.rb +49 -0
  56. data/rules.d/html.rule.rb +169 -0
  57. data/rules.d/js.jquery.rule.rb +49 -0
  58. data/rules.d/js.rule.rb +205 -0
  59. data/test/default_test.rb +14 -0
  60. data/test/fixtures/js/scope-test.js +15 -2
  61. data/test/test_helper.rb +9 -0
  62. metadata +269 -221
  63. data/lib/base_parser.rb +0 -143
  64. data/lib/cmd_runner.rb +0 -145
  65. data/lib/context.rb +0 -31
  66. data/lib/css/reader.rb +0 -30
  67. data/lib/css/rule/check_compression_rule.rb +0 -48
  68. data/lib/css/rule/checklist.rb +0 -45
  69. data/lib/helper/code_type.rb +0 -50
  70. data/lib/helper/color_string.rb +0 -44
  71. data/lib/helper/file_reader.rb +0 -22
  72. data/lib/helper/strenc.rb +0 -65
  73. data/lib/js/expr/expr.rb +0 -66
  74. data/lib/js/expr/left_hand.rb +0 -63
  75. data/lib/js/expr/operate.rb +0 -92
  76. data/lib/js/expr/primary.rb +0 -166
  77. data/lib/js/rule/all.rb +0 -35
  78. data/lib/js/rule/checklist.rb +0 -41
  79. data/lib/js/rule/file_checker.rb +0 -42
  80. data/lib/js/rule/helper.rb +0 -96
  81. data/lib/js/rule/no_global.rb +0 -87
  82. data/lib/js/stat/if.rb +0 -25
  83. data/lib/js/stat/iter.rb +0 -85
  84. data/lib/js/stat/stat.rb +0 -117
  85. data/lib/js/stat/switch.rb +0 -65
  86. data/lib/js/stat/try.rb +0 -28
  87. data/lib/js/stat/var.rb +0 -40
  88. data/lib/js/struct.rb +0 -248
  89. data/lib/log_entry.rb +0 -49
  90. data/lib/node.rb +0 -28
  91. data/lib/parse_error.rb +0 -13
  92. data/lib/parser_visitable.rb +0 -138
  93. data/lib/printer/base_printer.rb +0 -24
  94. data/lib/printer/console_printer.rb +0 -66
  95. data/lib/printer/nocolor_printer.rb +0 -27
  96. data/lib/printer/vim_printer.rb +0 -19
  97. data/lib/rule.rb +0 -241
  98. data/lib/rule_helper.rb +0 -14
  99. data/lib/runner.rb +0 -225
  100. data/rules.d/css.rule +0 -127
  101. data/rules.d/html.dtd.rule +0 -22
  102. data/rules.d/html.prop.rule +0 -51
  103. data/rules.d/html.tag.rule +0 -136
  104. data/rules.d/js.file.rule +0 -13
  105. data/rules.d/js.jquery.rule +0 -56
  106. data/rules.d/js.mergefile.rule +0 -71
  107. data/rules.d/js.rule +0 -84
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d9d6d40f7557d99e016ca0dfe7949ff1fa69d856
4
+ data.tar.gz: 558d82918d7b4f6e1b4901fa69201e5e7539056d
5
+ SHA512:
6
+ metadata.gz: 50b3ac1298038655d9fd0a89295f22d865780f79528f9b77ed65f47d967ee07d13aa1ecb2d156b53ffc82db4939c94660bdb1c02191232b024138ad4e27333e6
7
+ data.tar.gz: 3f44299dbd47fdca59e2dbe0c5b6769f287bd20d865338f40669d41540479e4c024f2cd5b39a48e9958040e3daee29f32b46f04e5df248e0efd8331e80f74051
data/Gemfile CHANGED
@@ -1,9 +1,2 @@
1
- source "https://rubygems.org"
2
-
3
- gem 'win32console', platform: :mswin
4
-
5
- group :development do
6
- gem 'test-unit'
7
- gem 'rake'
8
- gem 'gem-this'
9
- end
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Gemfile.lock CHANGED
@@ -1,15 +1,25 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ fdlint (0.2.0.pre)
5
+ colored (~> 1.2)
6
+ gli (~> 2.9.0)
7
+ string_utf8 (~> 0.1.1)
8
+
1
9
  GEM
2
10
  remote: https://rubygems.org/
3
11
  specs:
4
- gem-this (0.3.7)
12
+ colored (1.2)
13
+ gli (2.9.0)
5
14
  rake (0.9.2.2)
15
+ string_utf8 (0.1.1)
6
16
  test-unit (2.4.8)
7
17
 
8
18
  PLATFORMS
9
19
  ruby
10
20
 
11
21
  DEPENDENCIES
12
- gem-this
13
- rake
22
+ bundler
23
+ fdlint!
24
+ rake (~> 0.9.2.2)
14
25
  test-unit
15
- win32console
data/Rakefile CHANGED
@@ -1,92 +1,16 @@
1
- task :default => [:test]
1
+ require 'rake/clean'
2
+ require 'rubygems'
3
+ require 'rubygems/package_task'
2
4
 
3
- desc "run unit tests"
4
- task :test do
5
- require_relative 'test/all_tests'
6
- end
7
-
8
-
9
- require "rubygems"
10
- require "rubygems/package_task"
11
- require "rdoc/task"
12
-
13
- require "rake/testtask"
14
- Rake::TestTask.new do |t|
15
- t.libs << "test"
16
- t.test_files = FileList["test/**/*_test.rb"]
17
- t.verbose = true
18
- end
19
-
20
-
21
- task :default => ["test"]
22
-
23
- # This builds the actual gem. For details of what all these options
24
- # mean, and other ones you can add, check the documentation here:
25
- #
26
- # http://rubygems.org/read/chapter/20
27
- #
28
- spec = Gem::Specification.new do |s|
29
-
30
- # Change these as appropriate
31
- s.name = "fdlint"
32
- s.version = "0.1.3"
33
- s.summary = "Code reviewer for web developing. Check your HTML/JS/CSS codes against bad codes."
34
- s.author = "qhwa,bencode"
35
- s.email = "qhwa@163.com,bencode@163.com"
36
- s.homepage = "https://github.com/qhwa/fdlint"
5
+ spec = eval(File.read('fdlint.gemspec'))
37
6
 
38
- s.has_rdoc = false
39
- s.extra_rdoc_files = %w(README.md)
40
- s.rdoc_options = %w(--main README.md)
41
-
42
- # Add any extra files to include in the gem
43
- s.files = %w(README.md Rakefile Gemfile.lock Gemfile) +
44
- Dir.glob("{bin,test,lib,rules.d}/**/*") -
45
- Dir.glob("test/fixtures/html/{cms,tmp}/**/*")
46
- s.executables = FileList["bin/**"].map { |f| File.basename(f) }
47
- s.require_paths = ["lib"]
48
-
49
- # If you want to depend on other gems, add them here, along with any
50
- # relevant versions
51
- #s.add_dependency("win32console")
52
-
53
- # If your tests use any gems, include them here
54
- s.add_development_dependency("rake")
55
- s.add_development_dependency("test-unit")
56
- end
57
-
58
- # This task actually builds the gem. We also regenerate a static
59
- # .gemspec file, which is useful if something (i.e. GitHub) will
60
- # be automatically building a gem for this project. If you're not
61
- # using GitHub, edit as appropriate.
62
- #
63
- # To publish your gem online, install the 'gemcutter' gem; Read more
64
- # about that here: http://gemcutter.org/pages/gem_docs
65
7
  Gem::PackageTask.new(spec) do |pkg|
66
- pkg.gem_spec = spec
67
8
  end
68
9
 
69
- desc "Build the gemspec file #{spec.name}.gemspec"
70
- task :gemspec do
71
- file = File.dirname(__FILE__) + "/#{spec.name}.gemspec"
72
- File.open(file, "w") {|f| f << spec.to_ruby }
73
- end
74
-
75
- # If you don't want to generate the .gemspec file, just remove this line. Reasons
76
- # why you might want to generate a gemspec:
77
- # - using bundler with a git source
78
- # - building the gem without rake (i.e. gem build blah.gemspec)
79
- # - maybe others?
80
- task :package => :gemspec
81
-
82
- # Generate documentation
83
- RDoc::Task.new do |rd|
84
- rd.main = "README.md"
85
- rd.rdoc_files.include("README.md", "lib/**/*.rb")
86
- rd.rdoc_dir = "rdoc"
10
+ require 'rake/testtask'
11
+ Rake::TestTask.new do |t|
12
+ t.libs << "test"
13
+ t.test_files = FileList['test/*_test.rb']
87
14
  end
88
15
 
89
- desc 'Clear out RDoc and generated packages'
90
- task :clean => [:clobber_rdoc, :clobber_package] do
91
- rm "#{spec.name}.gemspec"
92
- end
16
+ task :default => [:test,:features]
data/bin/fdlint CHANGED
@@ -1,14 +1,77 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'gli'
3
+ begin # XXX: Remove this begin/rescue before distributing your app
4
+ require 'fdlint'
5
+ require 'fdlint/cli'
6
+ rescue LoadError
7
+ STDERR.puts "In development, you need to use `bundle exec bin/fdlint` to run your app"
8
+ STDERR.puts "At install-time, RubyGems will make sure lib, etc. are in the load path"
9
+ STDERR.puts "Feel free to remove this message from bin/fdlint now"
10
+ exit 64
11
+ end
12
+
13
+ include GLI::App
14
+
15
+ program_desc 'Code reviewer for web developing. Check your HTML/JS/CSS codes against bad smells.'
16
+
17
+ version Fdlint::VERSION
18
+
19
+ desc 'Print debug logs'
20
+ switch [:d, :debug], negatable: false
21
+
22
+ desc "review codes"
23
+ arg_name 'path'
24
+ command [:review, :check] do |c|
25
+
26
+ %w(css js html).each do |type|
27
+ c.desc "check #{type} files only"
28
+ c.switch type.intern, negatable: false
29
+ end
30
+
31
+ c.desc "output format. Can be 'vim', 'console' or 'nocolor'."
32
+ c.default_value :console
33
+ c.flag :format, must_match: %w[console nocolor vim]
2
34
 
3
- unless Kernel.respond_to?(:require_relative)
4
- module Kernel
5
- def require_relative(path)
6
- require File.expand_path(path.to_str, File.dirname(caller[0]))
35
+ c.desc "ignore minified files"
36
+ c.default_value false
37
+ c.switch [:m, :"ignore-min"], negatable: false
38
+
39
+ c.desc "shortcut for '--format=list'"
40
+ c.switch [:l, :list], negatable: false
41
+
42
+ c.desc "charset for reading files"
43
+ c.default_value 'utf-8'
44
+ c.flag [:c, :charset]
45
+
46
+ c.desc "the log level for filter results"
47
+ c.default_value 'warn'
48
+ c.flag [:loglevel], must_match: %s[warn error faltal]
49
+
50
+ c.action do |global, opt, args|
51
+
52
+ if args.empty?
53
+ if $stdin.tty?
54
+ help_now! 'files required'
55
+ else
56
+ source = ARGF.read
57
+ end
7
58
  end
59
+
60
+ options = {
61
+
62
+ :log_level => opt[:loglevel],
63
+ :format => opt[:list] ? :nocolor : opt[:format],
64
+ :encoding => opt[:encoding],
65
+ :syntax => opt[:css] ? :css :
66
+ opt[:js] ? :js :
67
+ opt[:html] ? :html : nil,
68
+ :debug => global[:debug],
69
+ :files => args,
70
+ :text => source
71
+ }
72
+
73
+ Fdlint::CLI.run options
8
74
  end
9
75
  end
10
76
 
11
- require_relative '../lib/cmd_runner'
12
-
13
- trap("SIGINT") { puts "\nGoodbye!"; exit! }
14
- XRay::CMDRunner.run
77
+ exit run(ARGV)
data/lib/fdlint/cli.rb ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env ruby
2
+ require 'optparse'
3
+ require 'find'
4
+ require 'logger'
5
+ require 'fdlint/printer'
6
+ require 'fdlint/printer/vim_printer'
7
+ require 'fdlint/printer/nocolor_printer'
8
+ require 'fdlint/printer/console_printer'
9
+
10
+ module Fdlint
11
+
12
+ module CLI
13
+
14
+ def self.run( options )
15
+ Runner.new( options ).run
16
+ end
17
+
18
+ class Runner
19
+
20
+ attr_reader :options, :files
21
+
22
+ def initialize( options={} )
23
+ @options = options
24
+ @files = options[:files]
25
+ end
26
+
27
+ def run
28
+ # Windows 下默认是ANSI编码
29
+ # 我们需要使用 UTF-8 编码输出
30
+ IO.popen "chcp 65001" if ENV['OS'] =~ /windows/i
31
+
32
+ $logger = Logger.new(STDOUT).tap do |l|
33
+ l.level = options[:debug] ? Logger::DEBUG : Logger::FATAL
34
+ end
35
+
36
+ trap("SIGINT") { puts "\nGoodbye!"; exit! }
37
+
38
+ if text = @options[:text]
39
+ validate_content
40
+ elsif !@files.empty?
41
+ validate_files
42
+ end
43
+ end
44
+
45
+ protected
46
+
47
+ def validate_content
48
+ opt_for_validator = {
49
+ :code_type => options[:code_type],
50
+ :text => options[:text]
51
+ }
52
+ ::Fdlint::Validator.new( nil, opt_for_validator ).validate do |file, source, results|
53
+ printer.print( file, source, results )
54
+ end
55
+ end
56
+
57
+ def validate_files
58
+ files.each do |file|
59
+ validate_path file do |file, source, results|
60
+ printer.print( file, source, results )
61
+ end
62
+ end
63
+ end
64
+
65
+ def validate_path( path, &block )
66
+ if File.directory? path
67
+ validate_directory path
68
+ else
69
+ validate_file path
70
+ end
71
+ end
72
+
73
+ def validate_directory( dir )
74
+ Find.find dir do |f|
75
+ validate_file f unless File.directory? f
76
+ end
77
+ end
78
+
79
+ def validate_file( path )
80
+ ::Fdlint::Validator.new( path ).validate do |file, source, results|
81
+ printer.print( file, source, results )
82
+ end
83
+ end
84
+
85
+ private
86
+
87
+ def printer
88
+ @printer ||= printer_for( @options[:format] )
89
+ end
90
+
91
+ def printer_for format
92
+ mapping = {
93
+ :console => ::Fdlint::Printer::ConsolePrinter.new,
94
+ :nocolor => ::Fdlint::Printer::NoColorPrinter.new,
95
+ :vim => ::Fdlint::Printer::VimPrinter.new
96
+ }.tap {|hash| hash.default = hash[:console] }
97
+ mapping[format]
98
+ end
99
+
100
+ end
101
+ end
102
+ end
File without changes
@@ -0,0 +1,55 @@
1
+ module Fdlint
2
+ module Helper
3
+
4
+ class CodeType
5
+
6
+ class << self
7
+
8
+ def guess(text, filename=nil)
9
+ if filename && !filename.empty?
10
+ guess_by_name filename
11
+ else
12
+ guess_by_content text
13
+ end
14
+ end
15
+
16
+ def guess_by_name( filename )
17
+ case File.extname( filename )
18
+ when /\.css$/i
19
+ :css
20
+ when /\.js$/i
21
+ :js
22
+ else
23
+ :html #TODO: support more suffix
24
+ end
25
+ end
26
+
27
+ def guess_by_content(text)
28
+ return :html if html? text
29
+ return :css if css? text
30
+ :js #TODO: support more code syntaxes
31
+ end
32
+
33
+ def style_file?(filename)
34
+ File.extname( filename ) =~ /(css|js|html?)$/i
35
+ end
36
+
37
+ def scope(filename)
38
+ filename =~ /[\\\/]lib[\\\/]/ ? 'lib' : 'page'
39
+ end
40
+
41
+ private
42
+
43
+ def html?(text)
44
+ /^\s*</m =~ text
45
+ end
46
+
47
+ def css?(text)
48
+ /^\s*@/m =~ text or /^\s*([-\*:\.#_\w]+\s*)+\{/ =~ text
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,19 @@
1
+ require 'string/utf8'
2
+
3
+ module Fdlint
4
+ module Helper
5
+ module FileReader
6
+ extend self
7
+
8
+ # auto detect file encoding and read it.
9
+ # return with an array containing string
10
+ # and encoding
11
+ def readfile(path, opt={})
12
+ bin = File.read(path).utf8!
13
+ raise EncodingError.new unless bin.valid_encoding?
14
+ bin
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,35 @@
1
+ require 'logger'
2
+
3
+ module Fdlint; module Helper
4
+
5
+ # Public: Module Logger handles the in-application
6
+ # runtime logging. It helps user inspect
7
+ # details of application running.
8
+ module Logger
9
+
10
+ LEVELS = [:debug, :info, :warn, :error, :fatal]
11
+
12
+ # Public: log message with specificated log level
13
+ #
14
+ # msg - the message text to log
15
+ # level - debug / info / warn / error / fatal
16
+ #
17
+ # Returns nil
18
+ def log( msg, level = :info )
19
+ level = :info unless LEVELS.include?( level )
20
+ send level, msg
21
+ end
22
+
23
+ LEVELS.each do |method|
24
+ define_method method do |*args, &block|
25
+ logger.send method, *args, &block
26
+ end
27
+ end
28
+
29
+ def logger
30
+ $logger ||= ::Logger.new(STDOUT)
31
+ end
32
+
33
+ end
34
+
35
+ end; end
@@ -0,0 +1,51 @@
1
+ require 'colored'
2
+
3
+ module Fdlint
4
+
5
+ class LogEntry < Struct.new(:message, :level, :row, :column)
6
+
7
+ attr_accessor :validation
8
+
9
+ def initialize(message, level, row = 0, colmn = 0)
10
+ super
11
+ end
12
+
13
+ def to_s
14
+ "[#{level.to_s.upcase}] #{pos} #{message}"
15
+ end
16
+
17
+ def pos
18
+ row.nil? ? "" : "[#{row},#{column}]"
19
+ end
20
+
21
+ def error?
22
+ level == :error
23
+ end
24
+
25
+ def warn?
26
+ level == :warn
27
+ end
28
+
29
+ def fatal?
30
+ level == :fatal
31
+ end
32
+
33
+ def info?
34
+ level == :info
35
+ end
36
+
37
+ def desc
38
+ validation && validation.long_desc
39
+ end
40
+
41
+
42
+ end
43
+
44
+ class InvalidFileEncoding < LogEntry
45
+ def initialize
46
+ super "文件编码错误,无法正常读取", :fatal
47
+ end
48
+ end
49
+
50
+
51
+ end
@@ -0,0 +1,151 @@
1
+ require 'fdlint/parser/node'
2
+ require 'fdlint/parser/parse_error'
3
+ require 'fdlint/parser/position_info'
4
+ require 'strscan'
5
+
6
+ module Fdlint
7
+
8
+ module Parser
9
+
10
+ class BaseParser
11
+
12
+ include ::Fdlint::Helper::Logger
13
+
14
+ attr_reader :source
15
+
16
+ def initialize(text)
17
+ @source = text
18
+ text = filter_text(prepare_text(text))
19
+ @pos_info = PositionInfo.new text
20
+ @scanner = StringScanner.new text
21
+ @text_size = text.size
22
+ end
23
+
24
+ def skip_empty
25
+ @scanner.skip(/\s*/)
26
+ end
27
+
28
+ def skip(pattern, not_skip_empty = false)
29
+ not_skip_empty || skip_empty
30
+ pos = scanner_pos
31
+ unless @scanner.skip pattern
32
+ parse_error pattern
33
+ end
34
+ after_skip pattern
35
+ pos
36
+ end
37
+
38
+ def scanner_pos
39
+ pos = @text_size - @scanner.rest.size
40
+ @pos_info.locate pos
41
+ end
42
+
43
+ def check(pattern, not_skip_empty = false)
44
+ skip_empty = !not_skip_empty
45
+ if skip_empty && @scanner.check(/\s+/)
46
+ last_pos = @scanner.pos
47
+ @scanner.skip /\s+/
48
+ end
49
+ ret = @scanner.check pattern
50
+ @scanner.pos = last_pos if last_pos
51
+ ret
52
+ end
53
+
54
+ def scan(pattern, not_skip_empty = false)
55
+ node = raw_scan pattern, not_skip_empty
56
+ after_scan pattern
57
+ node
58
+ end
59
+
60
+ def raw_scan(pattern, not_skip_empty = false)
61
+ not_skip_empty || skip_empty
62
+ pos = scanner_pos
63
+ text = @scanner.scan pattern
64
+ text ? Node.new(text, pos) : parse_error(pattern)
65
+ end
66
+
67
+ def batch(name, stop = nil, skip_pattern = nil, not_skip_empty = false, &block)
68
+ first = true
69
+ result = []
70
+ while !@scanner.eos? &&
71
+ (stop ? batch_check(stop, skip_pattern, not_skip_empty, first) :
72
+ block ? block.call : true) &&
73
+ item = send(name)
74
+ result << item
75
+ first = false
76
+ end
77
+ result
78
+ end
79
+
80
+ def to_s
81
+ self.class.to_s
82
+ end
83
+
84
+ def reset
85
+ @scanner.reset
86
+ end
87
+
88
+ def eos?
89
+ @scanner.eos?
90
+ end
91
+
92
+ def scanned_source
93
+ pos = @text_size - @scanner.rest.size
94
+ source[0..(pos-1)]
95
+ end
96
+
97
+ def rest_source
98
+ @scanner.rest
99
+ end
100
+
101
+ protected
102
+
103
+ def filter_text(text)
104
+ text
105
+ end
106
+
107
+ def after_skip(pattern)
108
+ end
109
+
110
+ def after_scan(pattern)
111
+ end
112
+
113
+ def parse_warn(message)
114
+ pos = scanner_pos
115
+ log "#{message}#{pos}", :warn
116
+ end
117
+
118
+ def parse_error(pattern)
119
+ if pattern.respond_to?(:source)
120
+ message = "should be #{pattern.source} here"
121
+ else
122
+ message = pattern.to_s
123
+ end
124
+ pos = scanner_pos
125
+ log "#{message} #{pos}", :error
126
+ raise ParseError.new(message, pos)
127
+ end
128
+
129
+ private
130
+
131
+ def prepare_text(text)
132
+ if text.respond_to? :encode!
133
+ text.encode! 'utf-8', :invalid => :replace, :universal_newline => true
134
+ else
135
+ text.gsub(/\r\n/, "\n").gsub(/\r/, "\n")
136
+ end
137
+ end
138
+
139
+ def batch_check(stop, skip_pattern, not_skip_empty, first)
140
+ if check stop, not_skip_empty
141
+ false
142
+ else
143
+ !first && skip_pattern && skip(skip_pattern)
144
+ true
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+ end
151
+ end