syntaxer 0.4.0 → 0.5.0

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.
@@ -1,3 +1,7 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
2
+ pp File.join(File.dirname(__FILE__), '..', 'lib')
1
3
  require 'aruba/cucumber'
2
4
  require 'fileutils'
3
- require "git"
5
+ require "git"
6
+ require 'syntaxer'
7
+ require 'cucumber/rspec/doubles'
@@ -5,22 +5,28 @@ require "forwardable"
5
5
  require "git"
6
6
  require "rainbow"
7
7
  require 'progress_bar'
8
+ require 'highline'
9
+ require "highline/import"
8
10
  require File.join(%w{syntaxer reader})
9
11
  require File.join(%w{syntaxer file_status})
10
12
  require File.join(%w{syntaxer checker})
13
+ require File.join(%w{syntaxer runner})
11
14
  require File.join(%w{syntaxer repository})
12
15
  require File.join(%w{syntaxer language_definition})
13
16
  require File.join(%w{syntaxer printer})
14
17
  require File.join(%w{syntaxer progress_bar})
18
+ require File.join(%w{syntaxer wizzard})
19
+ require File.join(%w{syntaxer writer})
15
20
 
16
21
  require File.join(%w{syntaxer railtie}) if defined?(Rails)
17
22
 
18
23
  module Syntaxer
19
24
  DEFAULT_FILES_MASK = "**/*"
20
25
  SYNTAXER_RULES_FILE = File.join(File.dirname(__FILE__), "..", "syntaxer_rules.dist.rb")
26
+ SYNTAXER_CONFIG_FILE_NAME = "syntaxer.rb"
21
27
 
22
28
  class << self
23
- attr_reader :reader, :repository, :root_path, :results, :warnings, :hook
29
+ attr_reader :reader, :repository, :root_path, :results, :warnings, :hook, :jslint
24
30
 
25
31
  def configure
26
32
  yield(self) if block_given?
@@ -38,17 +44,27 @@ module Syntaxer
38
44
 
39
45
  def check_syntax(options = {})
40
46
  @root_path = options[:root_path]
41
- Printer.quite = options[:quite] || false
42
- Printer.loud = options[:loud] || false
43
47
  @warnings = options[:warnings]
44
48
  @hook = options[:hook]
49
+ @jslint = options[:jslint]
50
+ Printer.quite = options[:quite] || false
51
+ Printer.loud = options[:loud] || false
45
52
 
46
53
  @reader = Reader::DSLReader.load(options[:config_file])
54
+
55
+ if @jslint # if jslint option passed set from command line we have to add new rule with indicated dir
56
+ rule = LanguageDefinition.new(:javascript, %w{js}, nil, [@jslint+"*", @jslint+"**/*"], nil, nil, nil, true, true)
57
+ rule.exec_rule = Runner.javascript.call
58
+ @reader.add_rule rule
59
+ end
60
+
47
61
  @repository = Repository.factory(@root_path, options[:repository]) if options[:repository]
48
-
62
+
63
+ $stdmyout = StringIO.new
49
64
  checker = Checker.process(self)
50
65
  Printer.print_result checker
51
- exit(1) unless checker.error_files.empty?
66
+
67
+ exit(1) unless checker.error_files.empty? && $stdmyout.string.empty?
52
68
  end
53
69
 
54
70
  # This method generate and put hook to .git/hooks
@@ -63,20 +79,37 @@ module Syntaxer
63
79
  @root_path = options[:root_path]
64
80
  raise ArgumentError, 'Indicate repository type' unless options.include?(:repository)
65
81
  raise ArgumentError, "SVN is temporarily not supported" if options[:repository].to_sym == :svn
66
-
67
- repo = Repository.factory(@root_path, options[:repository])
82
+
68
83
  hook_file = "#{@root_path}/.git/hooks/pre-commit"
69
- hook_string = "syntaxer -r git --hook"
70
- hook_string += " -c config/syntaxer.rb" if options[:rails]
84
+ hook_string = 'syntaxer '
85
+
86
+ if options[:restore] && File.exist?(File.join(@root_path,'.syntaxer'))
87
+ hook_string += File.open(File.join(@root_path,'.syntaxer')).read
88
+ else
89
+ repo = Repository.factory(@root_path, options[:repository])
90
+ hook_string += "-r git --hook"
91
+ hook_string += " -c config/syntaxer.rb" if options[:rails]
92
+ hook_string += " -c #{options[:config_file]}" unless options[:config_file].nil?
93
+ end
71
94
 
72
95
  File.open(hook_file, 'w') do |f|
73
96
  f.puts hook_string
74
97
  end
75
98
  File.chmod(0755, hook_file)
99
+
100
+ # save syntaxer options
101
+ File.open(File.join(options[:root_path],'.syntaxer'), 'w') do |f|
102
+ f.write(hook_string.gsub('syntaxer ',''))
103
+ end
104
+
76
105
  rescue Exception => e
77
106
  puts e.message.color(:red)
78
107
  raise e
79
108
  end
109
+
110
+ def wizzard(options)
111
+ Wizzard.start
112
+ end
80
113
 
81
114
  end
82
115
  end
@@ -1,8 +1,9 @@
1
1
  require 'set'
2
2
  require "observer"
3
+ require 'thread'
3
4
  module Syntaxer
4
5
  class Checker
5
- include Open3
6
+ # include Open3
6
7
  include Observable
7
8
  extend Forwardable
8
9
 
@@ -43,20 +44,14 @@ module Syntaxer
43
44
  notify_observers({:rule => rule})
44
45
  else
45
46
  if @syntaxer.warnings && rule.name == :ruby
46
- rule.exec_rule = rule.exec_rule.gsub(/(-\S+)\s/,'\1w ')
47
+ rule.exec_rule.exec_rule = rule.exec_rule.exec_rule.gsub(/(-\S+)\s/,'\1w ')
47
48
  end
48
- errors = run_exec_rule(rule, file)
49
+ errors = rule.exec_rule.run(file)
49
50
  FileStatus.build(file, errors)
50
51
  notify_observers({:file_status => errors.empty?})
51
52
  end
52
53
  end
53
54
 
54
- def run_exec_rule rule, file
55
- popen3(rule.exec_rule.gsub('%filename%', file)) do |stdin, stdout, stderr, wait_thr|
56
- stderr.read.split("\n")
57
- end
58
- end
59
-
60
55
  end
61
56
 
62
57
  # Check status of files in repository
@@ -64,7 +59,27 @@ module Syntaxer
64
59
  class RepoChecker < Checker
65
60
 
66
61
  def initialize syntaxer
67
- super syntaxer, syntaxer.repository.changed_and_added_files.length
62
+ @syntaxer = syntaxer
63
+ count_of_files = 0
64
+ @rule_files = {}
65
+ @deferred_process = []
66
+ syntaxer.reader.rules.each do |rule|
67
+ @rule_files[rule.name] = {}
68
+ @rule_files[rule.name][:rule] = rule
69
+ @rule_files[rule.name][:files] = []
70
+ rule.extensions.each do |ext|
71
+ files.each do |file|
72
+ if File.extname(file).gsub(/\./,'') == ext || \
73
+ (!rule.specific_files.nil? && !@rule_files[rule.name][:files].include?(file) && rule.specific_files.include?(file))
74
+
75
+ @rule_files[rule.name][:files].push(file)
76
+ count_of_files += 1 if !rule.deferred # skip these files
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ super syntaxer, count_of_files
68
83
  end
69
84
 
70
85
  # Check syntax in repository directory
@@ -72,28 +87,19 @@ module Syntaxer
72
87
  # @see Checker#process
73
88
 
74
89
  def process
75
- checked_files = Set.new
76
- rule_files = {}
77
-
78
- @reader.rules.each do |rule|
79
- rule_files[rule.name] = {}
80
- rule_files[rule.name][:rule] = rule
81
- rule_files[rule.name][:files] = []
82
- rule.extensions.each do |ext|
83
- files.each do |file|
84
- if File.extname(file).gsub(/\./,'') == ext || \
85
- (!rule.specific_files.nil? && !rule_files[rule.name][:files].include?(file) && rule.specific_files.include?(file))
86
- rule_files[rule.name][:files].push(file)
87
- end
90
+ @rule_files.each do |rule_name, rule|
91
+ if rule[:rule].deferred
92
+ @deferred_process << rule
93
+ else
94
+ rule[:files].each do |file|
95
+ full_path = File.join(@syntaxer.root_path,file)
96
+ check(rule[:rule], full_path)
88
97
  end
89
98
  end
90
99
  end
91
100
 
92
- rule_files.each do |rule_name, rule|
93
- rule[:files].each do |file|
94
- full_path = File.join(@syntaxer.root_path,file)
95
- check(rule[:rule], full_path)
96
- end
101
+ @deferred_process.each do |rule|
102
+ rule[:rule].exec_rule.run(@syntaxer.root_path, rule[:files])
97
103
  end
98
104
 
99
105
  self
@@ -116,13 +122,21 @@ module Syntaxer
116
122
  # @see Checker#process
117
123
 
118
124
  def process
125
+ @deferred_process = []
119
126
  @reader.rules.each do |rule|
120
- # check if executor exists
121
- rule.files_list(@syntaxer.root_path).each do |file|
122
- check(rule, file)
127
+ if rule.deferred
128
+ @deferred_process << rule
129
+ else
130
+ rule.files_list(@syntaxer.root_path).each do |file|
131
+ check(rule, file)
132
+ end
123
133
  end
124
134
  end
125
135
 
136
+ @deferred_process.each do |rule|
137
+ rule.exec_rule.run(@syntaxer.root_path, rule.files_list(@syntaxer.root_path))
138
+ end
139
+
126
140
  self
127
141
  end
128
142
 
@@ -1,7 +1,7 @@
1
1
  module Syntaxer
2
2
  class LanguageDefinitionException < Exception; end
3
3
 
4
- LanguageDefinition = Struct.new(:name, :extensions, :specific_files, :folders, :ignore_folders, :exec_rule, :executor, :exec_existence) do
4
+ LanguageDefinition = Struct.new(:name, :extensions, :specific_files, :folders, :ignore_folders, :exec_rule, :executor, :exec_existence, :deferred) do
5
5
  def initialize(*args)
6
6
  super(*args)
7
7
  raise LanguageDefinitionException.new "name can't be blank" unless self.name
@@ -29,8 +29,6 @@ module Syntaxer
29
29
  return if @quite
30
30
  if args.include?(:file_status)
31
31
  @mode == :hook ? @@bar.increment!(args[:file_status]) : @@bar.increment!
32
- # @@bar.increment!(args[:file_status]) if @mode == :hook
33
- # @@bar.increment! unless @mode == :hook
34
32
  end
35
33
  true
36
34
  end
@@ -42,19 +40,21 @@ module Syntaxer
42
40
  def print_result checker
43
41
  return if @quite
44
42
  puts "\n"
45
- puts "Syntax OK".color(:green) if checker.error_files.empty?
43
+ puts "Syntax OK".color(:green) if checker.error_files.empty? && $stdmyout.string.empty?
46
44
 
47
45
  @loud ? (files = checker.all_files) : (files = checker.error_files)
48
46
  files.each do |file|
49
47
  print_message(file)
50
48
  end
51
-
49
+
52
50
  unless @@not_exists_rules.empty?
53
51
  puts "\n"
54
52
  @@not_exists_rules.each do |rule|
55
53
  puts (NON_EXISTENT_RULE_MESSAGE % [rule.executor, rule.name]).color(:yellow)
56
54
  end
57
55
  end
56
+
57
+ $stderr.puts("\nErrors:"+"\n\t"+$stdmyout.string.color(:red)) unless $stdmyout.string.empty?
58
58
  end
59
59
 
60
60
  def print_message filestatus
@@ -4,9 +4,18 @@ module Syntaxer
4
4
  if defined? Rails::Railtie
5
5
  require 'rails'
6
6
  class Railtie < Rails::Railtie
7
+
7
8
  rake_tasks do
8
9
  load "tasks/syntaxer.rake"
9
10
  end
11
+
12
+ initializer "syntaxer.initialize" do |app|
13
+ if app.root.join('.syntaxer').exist? && !app.root.join('.git/hooks/pre-commit').exist? && Rails.env.development?
14
+ Syntaxer.make_hook({:root_path => app.root, :repository => :git, :rails => true, :restore => true})
15
+ puts "Syntaxer hook restored.".color(:green)
16
+ end
17
+ end
18
+
10
19
  end
11
20
  end
12
21
  end
@@ -14,9 +14,18 @@ module Syntaxer
14
14
  @ignore_folders = []
15
15
  end
16
16
 
17
+ def add_rule rule
18
+ @rules << rule
19
+ self
20
+ end
21
+
17
22
  def files_count syntaxer
18
23
  @rules.map{ |rule|
19
- rule.files_list(syntaxer.root_path).length
24
+ if rule.deferred
25
+ 0 # skip such files
26
+ else
27
+ rule.files_list(syntaxer.root_path).length
28
+ end
20
29
  }.inject(:+)
21
30
  end
22
31
 
@@ -123,11 +132,25 @@ module Syntaxer
123
132
  def specific_files(*args)
124
133
  current_rule.specific_files = args
125
134
  end
126
-
135
+
136
+ # Create exec rule for language. It may be console string and
137
+ # ruby method
138
+ #
139
+ # @param [String|Proc]
127
140
  def exec_rule(exec_string)
128
- current_rule.executor = exec_string.scan(/\w+/).first
129
- current_rule.exec_existence = system("which #{current_rule.executor} > /dev/null")
130
- current_rule.exec_rule = exec_string
141
+ # if it is string create default console runner
142
+ if !exec_string.respond_to?(:call) || exec_string.is_a?(String)
143
+ current_rule.executor = exec_string.scan(/\w+/).first
144
+ current_rule.exec_existence = system("which #{current_rule.executor} > /dev/null")
145
+ exec_rule = Syntaxer::Runner.default(exec_string)
146
+ current_rule.deferred = false
147
+ else
148
+ # if it is proc call it and pass current rule
149
+ current_rule.exec_existence = true
150
+ current_rule.deferred = true # we have run it after all console checkers
151
+ exec_rule = exec_string.call
152
+ end
153
+ current_rule.exec_rule = exec_rule
131
154
  end
132
155
 
133
156
  def ignore_folders(ignore_folders)
@@ -0,0 +1,57 @@
1
+ require 'jslint'
2
+
3
+ module Syntaxer
4
+ class Runner
5
+ include Open3
6
+
7
+ attr_accessor :exec_rule, :language
8
+
9
+ def initialize exec_rule = nil
10
+ @exec_rule = exec_rule
11
+ end
12
+
13
+ class << self
14
+ def javascript
15
+ lambda do
16
+ c = Syntaxer::Runner.new
17
+ c.language = 'javascript' # it is using for backward compatibility
18
+ c.extend(Runners::Javascript)
19
+ c
20
+ end
21
+ end
22
+
23
+ def default exec_rule
24
+ c = self.new(exec_rule)
25
+ c.extend(Runners::Default)
26
+ c
27
+ end
28
+ end
29
+ end
30
+
31
+ module Runners
32
+
33
+ module Default
34
+ def run file
35
+ result = Open3.popen3(@exec_rule.gsub('%filename%', file)) do |stdin, stdout, stderr, wait_thr|
36
+ stderr.read.split("\n")
37
+ end
38
+ result
39
+ end
40
+ end
41
+
42
+ module Javascript
43
+ def run(root, files = [])
44
+ puts ''
45
+ JSLint::Lint.new(
46
+ :paths => files,
47
+ :config_path => 'config/jslint.yml'
48
+ ).run
49
+ []
50
+ rescue JSLint::LintCheckFailure
51
+ $stdmyout.puts "jslint checking failed"
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,116 @@
1
+ module Syntaxer
2
+ class Wizzard
3
+ # Interactive console wizzard
4
+ LANG = [:ruby, :haml, :sass, :javascript]
5
+ FOLDERS_RAILS = {
6
+ :ruby => ["app/*", "app/**/*", "lib/*", "lib/**/*"],
7
+ :haml => ["app/views/*", "app/views/**/*"],
8
+ :sass => ["public/stylesheets/sass/*", "public/stylesheets/sass/**/*"],
9
+ :javascript => ["public/javascript/*", "public/javascript/**/*"]
10
+ }
11
+ DEFAULT_GLOB = ["*/*", "**/*"]
12
+ FOLDERS = {
13
+ :ruby => DEFAULT_GLOB,
14
+ :haml => DEFAULT_GLOB,
15
+ :sass => DEFAULT_GLOB,
16
+ :javascript => DEFAULT_GLOB
17
+ }
18
+
19
+ attr_accessor :options
20
+
21
+ def initialize options
22
+ @options = options
23
+ end
24
+
25
+ def run
26
+ FileUtils.mkdir_p(@options[:config_path]) if !@options[:config_dir_exists] && @options[:create_config_dir]
27
+ config_full_path = File.join(@options[:config_path], Syntaxer::SYNTAXER_CONFIG_FILE_NAME)
28
+ File.open(config_full_path, 'w') do |f|
29
+ f.write(config)
30
+ end
31
+
32
+ if @options[:git]
33
+ options = {:root_path => @options[:root_path], :repository => :git, :config_file => File.join(@options[:config_path], Syntaxer::SYNTAXER_CONFIG_FILE_NAME)}
34
+ options.merge!({:rails => true}) if options[:rails]
35
+ Syntaxer.make_hook(options)
36
+ end
37
+
38
+ if @options[:rails] && @options[:languages].include?(:javascript)
39
+ system('rake jslint:copy_config')
40
+ end
41
+ end
42
+
43
+ def config
44
+ reader = Reader::DSLReader.build
45
+ writer = Writer.new(@options[:languages], reader.rules)
46
+ writer.get_config
47
+ end
48
+
49
+ class << self
50
+
51
+ def start
52
+ options = {}
53
+ options[:root_path] = Dir.getwd
54
+ rails = false
55
+ say("Some greeting message. Hello God of this computer! Please answer in couple of question:".color(:green))
56
+
57
+ # ask for the languages to install
58
+ to_install = []
59
+ LANG.each do |lang|
60
+ if agree("Install support of #{lang.to_s.capitalize}? (y/n)".color(:yellow))
61
+ default_paths = rails? ? FOLDERS_RAILS[lang] : FOLDERS[lang]
62
+ paths = ask("Paths to check separated by comma (default are #{default_paths.inspect}):".color(:yellow))
63
+ if paths.empty?
64
+ paths = default_paths
65
+ else
66
+ paths = paths.split(',').map{|l| l.gsub(/\s/,'')}
67
+ end
68
+ to_install.push([lang, paths])
69
+ end
70
+ end
71
+
72
+ options[:languages] = to_install
73
+
74
+ # ask for path to save config
75
+ if rails?
76
+ say("Rails application detected. Config file saved to config/synaxer.rb".color(:green))
77
+ rails = true
78
+ config_path = "config"
79
+ else
80
+ config_path = ask("Specify where to save syntaxer's config file (./ by default):".color(:yellow))
81
+ config_path = '.' if config_path.empty?
82
+ expanded_config_path = File.expand_path(config_path)
83
+ options[:config_dir_exists] = FileTest.directory?(expanded_config_path)
84
+ options[:create_config_dir] = agree("No such directory found #{expanded_config_path}. Create it?".color(:green)) unless options[:config_dir_not_exists]
85
+ end
86
+
87
+ options[:rails] = rails
88
+ options[:config_path] = config_path
89
+
90
+ # trying to detect GIT
91
+ begin
92
+ g = ::Git.open(options[:root_path])
93
+ options[:git] = agree("Found git repo in #{File.expand_path(options[:root_path])}. Would you like install hook to check syntax before every commit? (y/n)".color(:yellow))
94
+ rescue
95
+ options[:git] = false
96
+ end
97
+
98
+ Wizzard.new(options).run
99
+
100
+ # buy message
101
+ say("Syntaxer is configured and installed. You can edit config in #{File.join(config_path, Syntaxer::SYNTAXER_CONFIG_FILE_NAME)}".color(:green))
102
+
103
+ rescue Interrupt => e
104
+ # external quit
105
+ puts "\nBuy"
106
+ end
107
+
108
+ private
109
+
110
+ def rails?
111
+ FileTest.directory?("config") && FileTest.file?("config/application.rb") && FileTest.file?("config/routes.rb")
112
+ end
113
+
114
+ end
115
+ end
116
+ end