oct 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,8 @@
1
- $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
- require 'rubygems'
3
1
  require 'oct'
4
- require 'aruba'
5
- require 'spec/expectations'
2
+ require 'aruba/cucumber'
3
+ require 'rspec/expectations'
4
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec/aruba_helper')
5
+
6
+ Before do
7
+ @aruba_timeout_seconds = 10
8
+ end
data/lib/oct/app.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'configatron'
2
1
  require 'term/ansicolor'
3
2
 
4
3
  class String
@@ -11,21 +10,26 @@ module Oct
11
10
 
12
11
  class App
13
12
 
14
- def initialize(base_dir, options={})
15
- @base_dir = base_dir
13
+ def initialize(working_dir, argv=[], options={})
14
+ @working_dir = working_dir
16
15
  @options = options
16
+ @argv = argv
17
17
  if @options[:verbose]
18
- puts "base_dir: #{@base_dir}".cyan
18
+ puts "working_dir: #{@working_dir}".cyan
19
19
  puts "options: #{@options.inspect}".cyan
20
+ puts "base_dir: #{@options[:base_dir]}".cyan if @options[:base_dir]
21
+ puts "config file: #{@options[:config]}".cyan if @options[:config]
20
22
  end
21
- configure(options)
23
+ $stdout.sync = true
22
24
  end
23
25
 
24
- def run
26
+ def execute
25
27
  begin
26
28
 
27
29
  if action_argument_required?
28
- action = ARGV.shift
30
+ action = @argv.shift
31
+ args = @argv
32
+
29
33
  unless AVAILABLE_ACTIONS.include?(action)
30
34
  if action.nil?
31
35
  puts "oct action required"
@@ -35,9 +39,9 @@ module Oct
35
39
  puts "oct --help for more information"
36
40
  exit 1
37
41
  end
38
- puts "oct run action: #{action}".cyan if @options[:verbose]
42
+ puts "oct run action: #{action} #{args.join(' ')}".cyan if @options[:verbose]
39
43
  raise "action #{action} not implemented" unless respond_to?(action)
40
- result = send(action)
44
+ result = send(action, args)
41
45
  else
42
46
  #
43
47
  # default action if action_argument_required? is false
@@ -46,7 +50,12 @@ module Oct
46
50
  result = Oct::FileStat.new.mode(files, @options)
47
51
  end
48
52
 
49
- exit(result ? 0 : 1)
53
+ if result.is_a?(Numeric)
54
+ exit(result)
55
+ else
56
+ # handle all other return types
57
+ exit(result ? 0 : 1)
58
+ end
50
59
 
51
60
  rescue SystemExit => e
52
61
  # This is the normal exit point, exit code from the send result
@@ -56,6 +65,7 @@ module Oct
56
65
  rescue Exception => e
57
66
  STDERR.puts("oct command failed, error(s) follow:")
58
67
  STDERR.puts("#{e.message}".red)
68
+ STDERR.puts("Use '--verbose' for backtrace.") unless @options[:verbose]
59
69
  STDERR.puts(e.backtrace.join("\n")) if @options[:verbose]
60
70
  exit(1)
61
71
  end
@@ -65,7 +75,7 @@ module Oct
65
75
  # app commands start
66
76
  #
67
77
 
68
-
78
+
69
79
  #
70
80
  # app commands end
71
81
  #
@@ -77,26 +87,5 @@ module Oct
77
87
  !AVAILABLE_ACTIONS.empty?
78
88
  end
79
89
 
80
- # read options for YAML config with ERB processing and initialize configatron
81
- def configure(options)
82
- config = @options[:config]
83
- config = File.join(@base_dir, 'oct.conf') unless config
84
- if File.exists?(config)
85
- # load configatron options from the config file
86
- puts "loading config file: #{config}".cyan if @options[:verbose]
87
- configatron.configure_from_yaml(config)
88
- else
89
- # user specified a config file?
90
- raise "config file not found" if @options[:config]
91
- # no error if user did not specify config file
92
- puts "#{config} not found".yellow if @options[:verbose]
93
- end
94
-
95
- #
96
- # set defaults, these will NOT override setting read from YAML
97
- #
98
-
99
- end
100
-
101
90
  end
102
91
  end
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def recursively_symbolize_keys!
3
+ self.each do |item|
4
+ if item.is_a? Hash
5
+ item.recursively_symbolize_keys!
6
+ elsif item.is_a? Array
7
+ item.recursively_symbolize_keys!
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,45 @@
1
+ class Hash
2
+
3
+ # sorted yaml
4
+ def to_yaml( opts = {} )
5
+ YAML::quick_emit( object_id, opts ) do |out|
6
+ out.map( taguri, to_yaml_style ) do |map|
7
+ sorted_keys = keys
8
+ sorted_keys = begin
9
+ sorted_keys.sort
10
+ rescue
11
+ sorted_keys.sort_by {|k| k.to_s} rescue sorted_keys
12
+ end
13
+
14
+ sorted_keys.each do |k|
15
+ map.add( k, fetch(k) )
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # active_support hash key functions
22
+ def symbolize_keys!
23
+ self.replace(self.symbolize_keys)
24
+ end
25
+
26
+ def symbolize_keys
27
+ inject({}) do |options, (key, value)|
28
+ options[(key.to_sym rescue key) || key] = value
29
+ options
30
+ end
31
+ end
32
+
33
+ def recursively_symbolize_keys!
34
+ self.symbolize_keys!
35
+ self.values.each do |v|
36
+ if v.is_a? Hash
37
+ v.recursively_symbolize_keys!
38
+ elsif v.is_a? Array
39
+ v.recursively_symbolize_keys!
40
+ end
41
+ end
42
+ self
43
+ end
44
+
45
+ end
data/lib/oct/oct.rb CHANGED
@@ -9,7 +9,7 @@ module Oct
9
9
  puts "oct mode files: #{files.inspect}".cyan if options[:verbose]
10
10
  files.sort.each do |file|
11
11
  stat = File.stat(file)
12
- printf("%04o ", stat.mode & 07777)
12
+ printf("%04o ", stat.mode & 07777)
13
13
  if stat.directory?
14
14
  puts file.blue
15
15
  elsif stat.executable?
@@ -19,7 +19,7 @@ module Oct
19
19
  else
20
20
  puts file
21
21
  end
22
- end
22
+ end
23
23
  end
24
24
 
25
25
  end
@@ -0,0 +1,60 @@
1
+ require 'yaml'
2
+
3
+ module Oct
4
+
5
+ class Settings
6
+
7
+ def initialize(working_dir, options={})
8
+ @working_dir = working_dir
9
+ @options = options
10
+ configure
11
+ end
12
+
13
+ def options
14
+ @options
15
+ end
16
+
17
+ private
18
+
19
+ # read options from YAML config
20
+ def configure
21
+
22
+ # config file default options
23
+ configuration = {
24
+ :options => {
25
+ :verbose => false,
26
+ :color => 'AUTO'
27
+ }
28
+ }
29
+
30
+ # set default config if not given on command line
31
+ config = @options[:config]
32
+ unless config
33
+ config = [
34
+ File.join(@working_dir, "oct.conf"),
35
+ File.join(@working_dir, ".oct.conf"),
36
+ File.join(@working_dir, "config", "oct.conf"),
37
+ File.expand_path(File.join("~", ".oct.conf"))
38
+ ].detect { |filename| File.exists?(filename) }
39
+ end
40
+
41
+ if config && File.exists?(config)
42
+ # rewrite options full path for config for later use
43
+ @options[:config] = config
44
+
45
+ # load options from the config file, overwriting hard-coded defaults
46
+ config_contents = YAML::load(File.open(config))
47
+ configuration.merge!(config_contents.symbolize_keys!) if config_contents && config_contents.is_a?(Hash)
48
+ else
49
+ # user specified a config file?, no error if user did not specify config file
50
+ raise "config file not found" if @options[:config]
51
+ end
52
+
53
+ # the command line options override options read from the config file
54
+ @options = configuration[:options].symbolize_keys!.merge!(@options)
55
+
56
+ end
57
+
58
+ end
59
+
60
+ end
data/lib/oct.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # require all files here
2
2
  require 'rbconfig'
3
+ require 'oct/core/hash'
4
+ require 'oct/core/array'
3
5
  require 'oct/app'
6
+ require 'oct/settings'
4
7
  require 'oct/oct'
5
8
 
6
9
  # Master namespace
@@ -20,8 +23,8 @@ module Oct
20
23
 
21
24
  # Platform constants
22
25
  unless defined?(BasicGem::WINDOWS)
23
- WINDOWS = Config::CONFIG['host_os'] =~ /mswin|mingw/i
24
- CYGWIN = Config::CONFIG['host_os'] =~ /cygwin/i
26
+ WINDOWS = RbConfig::CONFIG['host_os'] =~ /mswin|mingw/i
27
+ CYGWIN = RbConfig::CONFIG['host_os'] =~ /cygwin/i
25
28
  end
26
29
 
27
30
  end
data/oct.gemspec CHANGED
@@ -1,30 +1,25 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  #
3
3
  #
4
-
5
4
  Gem::Specification.new do |s|
6
- # wrap 'git' so we can get gem files even on systems without 'git'
5
+
6
+ # avoid shelling out to run git every time the gemspec is evaluated
7
7
  #
8
8
  # @see spec/gemspec_spec.rb
9
9
  #
10
- @gemfiles ||= begin
11
- filename = File.join(File.dirname(__FILE__), '.gemfiles')
12
- # backticks blows up on Windows w/o valid binary, use system instead
13
- if File.directory?('.git') && system('git ls-files bogus-filename')
14
- files = `git ls-files`
15
- cached_files = File.exists?(filename) ? File.open(filename, "r") {|f| f.read} : nil
16
- # maintain EOL
17
- files.gsub!(/\n/, "\r\n") if cached_files && cached_files.match("\r\n")
18
- File.open(filename, 'wb') {|f| f.write(files)} if cached_files != files
19
- else
20
- files = File.open(filename, "r") {|f| f.read}
21
- end
22
- raise "unable to process gemfiles" unless files
23
- files.gsub(/\r\n/, "\n")
10
+ gemfiles_cache = File.join(File.dirname(__FILE__), '.gemfiles')
11
+ if File.exists?(gemfiles_cache)
12
+ gemfiles = File.open(gemfiles_cache, "r") {|f| f.read}
13
+ # normalize EOL
14
+ gemfiles.gsub!(/\r\n/, "\n")
15
+ else
16
+ # .gemfiles missing, run 'rake gemfiles' to create it
17
+ # falling back to 'git ls-files'"
18
+ gemfiles = `git ls-files`
24
19
  end
25
20
 
26
21
  s.name = "oct"
27
- s.version = File.open(File.join(File.dirname(__FILE__), 'VERSION'), "r") { |f| f.read }
22
+ s.version = File.open(File.join(File.dirname(__FILE__), 'VERSION'), "r") { |f| f.read }
28
23
  s.platform = Gem::Platform::RUBY
29
24
  s.authors = ["Robert Wahler"]
30
25
  s.email = ["robert@gearheadforhire.com"]
@@ -36,31 +31,25 @@ Gem::Specification.new do |s|
36
31
  s.rubyforge_project = "oct"
37
32
 
38
33
  s.add_dependency 'term-ansicolor', '>= 1.0.4'
39
- s.add_dependency 'configatron', '>= 2.5.1'
40
34
 
41
- s.add_development_dependency "bundler", ">= 1.0.7"
42
- s.add_development_dependency "rspec", "= 1.3.1"
43
- s.add_development_dependency "cucumber", ">= 0.9.4"
44
- s.add_development_dependency "aruba", ">= 0.2.2"
35
+ s.add_development_dependency "bundler", ">= 1.0.14"
36
+ s.add_development_dependency "rspec", ">= 2.6.0"
37
+ s.add_development_dependency "cucumber", "~> 1.0"
38
+ s.add_development_dependency "aruba", "~> 0.4.3"
45
39
  s.add_development_dependency "rake", ">= 0.8.7"
46
- s.add_development_dependency "yard", ">= 0.6.2"
47
-
48
- # Specify a markdown gem for rake doc:generate
49
- #
50
- # Without the development dependency, running yard rake
51
- # tasks will fail. Kramdown chosen to provide a pure Ruby solution.
52
- s.add_development_dependency "kramdown", ">= 0.12.0"
53
40
 
54
- s.files = @gemfiles.split("\n")
55
- s.executables = @gemfiles.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
41
+ # doc generation
42
+ s.add_development_dependency "yard", ">= 0.7.2"
43
+ s.add_development_dependency "redcarpet", ">= 1.17.2"
56
44
 
57
- s.require_path = 'lib'
45
+ s.files = gemfiles.split("\n")
46
+ s.executables = gemfiles.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
47
+ s.require_paths = ["lib"]
58
48
 
59
- s.has_rdoc = 'yard'
60
- s.rdoc_options = [
61
- '--title', 'Oct Documentation',
62
- '--main', 'README.markdown',
49
+ s.rdoc_options = [
50
+ '--title', 'Oct Documentation',
51
+ '--main', 'README.markdown',
63
52
  '--line-numbers',
64
- '--inline-source'
53
+ '--inline-source'
65
54
  ]
66
55
  end
@@ -0,0 +1,25 @@
1
+ module Aruba
2
+ module Api
3
+
4
+ # @return full path to files in the aruba tmp folder
5
+ def fullpath(filename)
6
+ path = File.expand_path(File.join(current_dir, filename))
7
+ if path.match(/^\/cygdrive/)
8
+ # match /cygdrive/c/path/to and return c:\\path\\to
9
+ path = `cygpath -w #{path}`.chomp
10
+ elsif path.match(/.\:/)
11
+ # match c:/path/to and return c:\\path\\to
12
+ path = path.gsub(/\//, '\\')
13
+ end
14
+ path
15
+ end
16
+
17
+ # @return the contents of "filename" in the aruba tmp folder
18
+ def get_file_contents(filename)
19
+ in_current_dir do
20
+ IO.read(filename)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ require 'spec_helper'
2
+
3
+ describe Array do
4
+
5
+ describe 'recursively_symbolize_keys!' do
6
+
7
+ it "should recursively convert a hash with string keys to a hash with symbol keys" do
8
+ hash_symbols = {
9
+ :options => {
10
+ :verbose => false,
11
+ },
12
+ :repos => {
13
+ :repo1 => {:path => "something"}
14
+ }
15
+ }
16
+
17
+ hash_strings = {
18
+ 'options' => {
19
+ 'verbose' => false,
20
+ },
21
+ 'repos' => {
22
+ 'repo1' => {'path' => "something"}
23
+ }
24
+ }
25
+
26
+ hash_symbols.should == hash_strings.recursively_symbolize_keys!
27
+ end
28
+
29
+ it "should should handle hashes that are already symbolized" do
30
+ hash_symbols = {
31
+ :options => {
32
+ :verbose => false,
33
+ },
34
+ :repos => {
35
+ :repo1 => {:path => "something"}
36
+ }
37
+ }
38
+
39
+ hash_copy = hash_symbols.dup
40
+
41
+ hash_copy.should == hash_symbols.recursively_symbolize_keys!
42
+ hash_symbols[:repos][:repo1].should == {:path => "something"}
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+
@@ -1,10 +1,10 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe Oct do
4
-
4
+
5
5
  before(:each) do
6
6
  @filename = 'input.txt'
7
- create_file(@filename, "the quick brown fox")
7
+ write_file(@filename, "the quick brown fox")
8
8
  end
9
9
 
10
10
  describe 'Aruba::API.current_dir' do
@@ -1,7 +1,7 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe Oct do
4
-
4
+
5
5
  describe 'version' do
6
6
 
7
7
  it "should return a string formatted '#.#.#'" do
@@ -10,4 +10,75 @@ describe Oct do
10
10
 
11
11
  end
12
12
 
13
+ # VIM autocmd to remove trailing whitespace
14
+ # autocmd BufWritePre * :%s/\s\+$//e
15
+ #
16
+ describe "code" do
17
+
18
+ before(:each) do
19
+ @gemfiles_filename = File.expand_path(File.dirname(__FILE__) + '/../../.gemfiles')
20
+ raise ".gemfiles not found. Please run 'rake gemfiles'" unless File.exists?(@gemfiles_filename)
21
+ @gemfiles = File.open(@gemfiles_filename, "rb") {|f| f.read}
22
+ @eol = @gemfiles.match("\r\n") ? "\r\n" : "\n"
23
+ end
24
+
25
+ def binary?(filename)
26
+ open filename do |f|
27
+ f.each_byte { |x|
28
+ x.nonzero? or return true
29
+ }
30
+ end
31
+ false
32
+ end
33
+
34
+ def check_for_tab_characters(filename)
35
+ failing_lines = []
36
+ File.readlines(filename).each_with_index do |line,number|
37
+ failing_lines << number + 1 if line =~ /\t/
38
+ end
39
+
40
+ unless failing_lines.empty?
41
+ "#{filename} has tab characters on lines #{failing_lines.join(', ')}"
42
+ end
43
+ end
44
+
45
+ def check_for_extra_spaces(filename)
46
+ failing_lines = []
47
+ File.readlines(filename).each_with_index do |line,number|
48
+ next if line =~ /^\s+#.*\s+#{@eol}$/
49
+ failing_lines << number + 1 if line =~ /\s+#{@eol}$/
50
+ end
51
+
52
+ unless failing_lines.empty?
53
+ "#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}"
54
+ end
55
+ end
56
+
57
+ RSpec::Matchers.define :be_well_formed do
58
+ failure_message_for_should do |actual|
59
+ actual.join("\n")
60
+ end
61
+
62
+ match do |actual|
63
+ actual.empty?
64
+ end
65
+ end
66
+
67
+ it "has no malformed whitespace" do
68
+ error_messages = []
69
+ @gemfiles.split(@eol).each do |filename|
70
+ filename = File.expand_path(File.join(File.dirname(__FILE__), ["..", "..", filename]))
71
+ unless File.exists?(filename)
72
+ puts "WARNING: .gemfiles out-of-date, #{filename} not found. Edit .gemfiles or run 'rake gemfiles' after committing changes."
73
+ next
74
+ end
75
+ next if filename =~ /\.gitmodules/
76
+ next if binary?(filename)
77
+ error_messages << check_for_tab_characters(filename)
78
+ error_messages << check_for_extra_spaces(filename)
79
+ end
80
+ error_messages.compact.should be_well_formed
81
+ end
82
+
83
+ end
13
84
  end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  describe Oct do
4
4
 
@@ -6,7 +6,7 @@ describe Oct do
6
6
  filename = File.expand_path('../../../oct.gemspec', __FILE__)
7
7
  eval(File.read(filename), nil, filename)
8
8
  end
9
-
9
+
10
10
  describe 'gemspec' do
11
11
 
12
12
  it "should return the gem VERSION" do
@@ -27,31 +27,19 @@ describe Oct do
27
27
  @gemspec.executables.is_a?(Array).should == true
28
28
  end
29
29
 
30
- describe 'without an existing cache' do
30
+ describe 'without .gemfiles cache' do
31
31
  before(:each) do
32
32
  File.stub!('exists?').and_return false
33
33
  @gemspec = load_gemspec
34
34
  end
35
35
 
36
- it "should not blow up" do
37
- @gemspec.files.is_a?(Array).should == true
38
- @gemspec.files.include?('VERSION').should == true
39
- end
40
- end
41
-
42
- describe 'without a git repo' do
43
- before(:each) do
44
- File.stub!('directory?').and_return false
45
- @gemspec = load_gemspec
46
- end
47
-
48
- it "should return 'files' from cache" do
49
- File.directory?(File.expand_path('../../../.git', __FILE__)).should == false
36
+ it "should return 'files' from using 'git ls-files" do
37
+ File.exists?(File.expand_path('../../../.gemfiles', __FILE__)).should == false
50
38
  @gemspec.files.is_a?(Array).should == true
51
39
  @gemspec.files.include?('VERSION').should == true
52
40
  end
53
- it "should return 'executables' from cache" do
54
- File.directory?(File.expand_path('../../../.git', __FILE__)).should == false
41
+ it "should return 'executables' from 'git ls-files" do
42
+ File.exists?(File.expand_path('../../../.gemfiles', __FILE__)).should == false
55
43
  @gemspec.executables.is_a?(Array).should == true
56
44
  end
57
45
  end
@@ -64,12 +52,12 @@ describe Oct do
64
52
  end
65
53
 
66
54
  it "should return 'files' from cache" do
67
- system('git --version').should == false
55
+ system('git --version').should == false
68
56
  @gemspec.files.is_a?(Array).should == true
69
57
  @gemspec.files.include?('VERSION').should == true
70
58
  end
71
59
  it "should return 'executables' from cache" do
72
- system('git --version').should == false
60
+ system('git --version').should == false
73
61
  @gemspec.executables.is_a?(Array).should == true
74
62
  end
75
63
 
data/spec/spec_helper.rb CHANGED
@@ -1,35 +1,11 @@
1
- $LOAD_PATH.unshift File.expand_path('..', __FILE__) unless
2
- $LOAD_PATH.include? File.expand_path('..', __FILE__)
3
- $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) unless
4
- $LOAD_PATH.include? File.expand_path('../../lib', __FILE__)
5
-
6
- require 'rubygems'
7
1
  require 'oct'
8
- require 'spec'
9
- require 'spec/autorun'
2
+ require 'rspec/core'
10
3
  require 'aruba/api'
4
+ require 'aruba_helper'
11
5
 
12
- # aruba helpers
13
- #
14
- # @return full path to files in the aruba tmp folder
15
- def fullpath(filename)
16
- path = File.expand_path(File.join(current_dir, filename))
17
- if path.match(/^\/cygdrive/)
18
- # match /cygdrive/c/path/to and return c:\\path\\to
19
- path = `cygpath -w #{path}`.chomp
20
- elsif path.match(/.\:/)
21
- # match c:/path/to and return c:\\path\\to
22
- path = path.gsub(/\//, '\\')
23
- end
24
- path
25
- end
26
- # @return the contents of "filename" in the aruba tmp folder
27
- def get_file_contents(filename)
28
- in_current_dir do
29
- IO.read(filename)
30
- end
31
- end
32
-
33
- Spec::Runner.configure do |config|
34
- config.include Aruba::Api
6
+ RSpec.configure do |config|
7
+ config.include Aruba::Api
8
+ config.filter_run :focus => true
9
+ config.run_all_when_everything_filtered = true
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
35
11
  end
data/spec/watchr.rb CHANGED
@@ -44,13 +44,15 @@ end
44
44
 
45
45
  def run(cmd)
46
46
 
47
+ cmd = 'bundle exec ' + cmd unless cmd.match(/^bundle exec/)
48
+
47
49
  pid = fork do
48
50
 
49
51
  puts "\n"
50
52
  if $c
51
53
  print $c.cyan, cmd, $c.clear, "\n"
52
54
  else
53
- puts cmd
55
+ puts cmd
54
56
  end
55
57
 
56
58
  exec(cmd)