fdlint 0.1.3 → 0.2.0.pre

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.
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