clintegracon 0.4.1

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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.travis.yml +12 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +158 -0
  7. data/Rakefile +60 -0
  8. data/clintegracon.gemspec +34 -0
  9. data/lib/CLIntegracon.rb +9 -0
  10. data/lib/CLIntegracon/adapter/bacon.rb +208 -0
  11. data/lib/CLIntegracon/configuration.rb +67 -0
  12. data/lib/CLIntegracon/diff.rb +81 -0
  13. data/lib/CLIntegracon/file_tree_spec.rb +213 -0
  14. data/lib/CLIntegracon/file_tree_spec_context.rb +180 -0
  15. data/lib/CLIntegracon/formatter.rb +77 -0
  16. data/lib/CLIntegracon/subject.rb +128 -0
  17. data/lib/CLIntegracon/version.rb +3 -0
  18. data/spec/bacon/execution_output.txt +72 -0
  19. data/spec/bacon/spec_helper.rb +60 -0
  20. data/spec/fixtures/bin/coffeemaker.rb +58 -0
  21. data/spec/integration/coffeemaker_help/after/execution_output.txt +23 -0
  22. data/spec/integration/coffeemaker_help/before/.gitkeep +0 -0
  23. data/spec/integration/coffeemaker_no_milk/after/BlackEye.brewed-coffee +1 -0
  24. data/spec/integration/coffeemaker_no_milk/after/CaPheSuaDa.brewed-coffee +1 -0
  25. data/spec/integration/coffeemaker_no_milk/after/Coffeemakerfile.yml +5 -0
  26. data/spec/integration/coffeemaker_no_milk/after/RedTux.brewed-coffee +1 -0
  27. data/spec/integration/coffeemaker_no_milk/after/execution_output.txt +6 -0
  28. data/spec/integration/coffeemaker_no_milk/before/Coffeemakerfile.yml +5 -0
  29. data/spec/integration/coffeemaker_sweetner_honey/after/Affogato.brewed-coffee +2 -0
  30. data/spec/integration/coffeemaker_sweetner_honey/after/BlackEye.brewed-coffee +2 -0
  31. data/spec/integration/coffeemaker_sweetner_honey/after/Coffeemakerfile.yml +3 -0
  32. data/spec/integration/coffeemaker_sweetner_honey/after/RedTux.brewed-coffee +2 -0
  33. data/spec/integration/coffeemaker_sweetner_honey/after/execution_output.txt +4 -0
  34. data/spec/integration/coffeemaker_sweetner_honey/before/Coffeemakerfile.yml +3 -0
  35. data/spec/unit/adapter/bacon_spec.rb +187 -0
  36. data/spec/unit/configuration_spec.rb +72 -0
  37. metadata +176 -0
@@ -0,0 +1,77 @@
1
+ require 'colored'
2
+
3
+ module CLIntegracon
4
+ class Formatter
5
+
6
+ # @return [FileTreeSpec]
7
+ # the spec
8
+ attr_reader :spec
9
+
10
+ # Initialize
11
+ #
12
+ # @param [FileTreeSpec] spec
13
+ # the spec
14
+ #
15
+ def initialize(spec)
16
+ super()
17
+ @spec = spec
18
+ end
19
+
20
+ # Return a description text for an expectation that a file path
21
+ # was expected to exist, but is missing.
22
+ #
23
+ # @param [Pathname] file_path
24
+ # the file path which was expected to exist
25
+ #
26
+ # @return [String]
27
+ #
28
+ def describe_missing_file(file_path)
29
+ description = []
30
+ description << "Missing file for #{spec.spec_folder}:"
31
+ description << " * #{file_path.to_s.red}"
32
+ description * "\n"
33
+ end
34
+
35
+ # Return a description text for an expectation that certain file paths
36
+ # were unexpected.
37
+ #
38
+ # @param [Array<Pathname>] file_paths
39
+ #
40
+ # @return [String]
41
+ #
42
+ def describe_unexpected_files(file_paths)
43
+ description = []
44
+ description << "Unexpected files for #{spec.spec_folder}:"
45
+ description += file_paths.map { |f| " * #{f.to_s.green}" }
46
+ description * "\n"
47
+ end
48
+
49
+ # Return a description text for an expectation that two files were
50
+ # expected to be the same, but are not.
51
+ #
52
+ # @param [Diff] diff
53
+ # the diff which holds the difference
54
+ #
55
+ # @param [Integer] max_width
56
+ # the max width of the terminal to print matching separators
57
+ #
58
+ # @return [String]
59
+ #
60
+ def describe_file_diff(diff, max_width=80)
61
+ description = []
62
+ description << "File comparison error `#{diff.relative_path}` for #{spec.spec_folder}:"
63
+ description << "--- DIFF ".ljust(max_width, '-')
64
+ description += diff.map do |line|
65
+ case line
66
+ when /^\+/ then line.green
67
+ when /^-/ then line.red
68
+ else line
69
+ end.gsub("\n",'')
70
+ end
71
+ description << "--- END ".ljust(max_width, '-')
72
+ description << ''
73
+ description * "\n"
74
+ end
75
+
76
+ end
77
+ end
@@ -0,0 +1,128 @@
1
+ module CLIntegracon
2
+ class Subject
3
+
4
+ #-----------------------------------------------------------------------------#
5
+
6
+ # @!group Attributes
7
+
8
+ # @return [String]
9
+ # The name of the binary to use for the tests
10
+ attr_accessor :name
11
+
12
+ # @return [String]
13
+ # The executable statement to use for the tests
14
+ attr_accessor :executable
15
+
16
+ # @return [Hash<String,String>]
17
+ # The environment variables which will always been defined for the executable
18
+ # on launch should not been passed explicitly every time to the launch method.
19
+ attr_accessor :environment_vars
20
+
21
+ # @return [Array<String>]
22
+ # The arguments which will always passed to the executable on launch and
23
+ # should not been passed explicitly every time to the launch method.
24
+ # Those are added behind the arguments given on +launch+.
25
+ attr_accessor :default_args
26
+
27
+ # @return [Hash<String,String>]
28
+ # The special paths, which are not relative to the project, when the statement
29
+ # will be executed. These are paths were side-effects occur, like manipulation
30
+ # of user configurations in dot files or caching-specific directories.
31
+ attr_accessor :special_paths
32
+
33
+ # @return [String]
34
+ # The path where the output of the executable will be written to.
35
+ attr_accessor :output_path
36
+
37
+
38
+ #-----------------------------------------------------------------------------#
39
+
40
+ # @!group Initializer
41
+
42
+ # "Designated" initializer
43
+ #
44
+ # @param [String] name
45
+ # The name of the binary
46
+ #
47
+ # @param [String] executable
48
+ # The executable subject statement (optional)
49
+ #
50
+ def initialize(name='subject', executable=nil)
51
+ self.name = name
52
+ self.executable = executable || name
53
+ self.environment_vars = {}
54
+ self.default_args = []
55
+ self.special_paths = {}
56
+ self.output_path = 'execution_output.txt'
57
+ end
58
+
59
+
60
+ #-----------------------------------------------------------------------------#
61
+
62
+ # @!group DSL-like Setter
63
+
64
+ # Define a path in the user directory as special path
65
+ #
66
+ # @param [String] path
67
+ # The path
68
+ #
69
+ # @param [String] name
70
+ # The name of the path, or the basename of the given path
71
+ #
72
+ def has_special_path(path, name=nil)
73
+ name ||= File.basename path
74
+ self.special_paths[name] = path
75
+ end
76
+
77
+ # Define a path in the user directory as special path
78
+ #
79
+ # @param [String] path
80
+ # The path
81
+ #
82
+ # @param [String] name
83
+ # The name of the path, or the basename of the given path
84
+ #
85
+ def has_special_user_path(path, name=nil)
86
+ self.has_special_path %r[/Users/.*/#{path.to_s}], name
87
+ end
88
+
89
+ #-----------------------------------------------------------------------------#
90
+
91
+ # @!group Interaction
92
+
93
+ # Runs the executable with the given arguments in the temporary directory.
94
+ #
95
+ # @note: You can check by `$?.success?` if the execution succeeded.
96
+ #
97
+ # @param [String] head_arguments
98
+ # The arguments to pass to the executable before the default arguments.
99
+ #
100
+ # @param [String] tail_arguments
101
+ # The arguments to pass to the executable after the default arguments.
102
+ #
103
+ # @return [String]
104
+ # The output, which is emitted while execution from the binary.
105
+ #
106
+ def launch(head_arguments='', tail_arguments='')
107
+ vars = environment_vars.map { |key,value| "#{key}=#{value}" }.join ' '
108
+ args = [head_arguments, default_args, tail_arguments].flatten.compact.select { |s| s.length > 0 }.join ' '
109
+ command = "#{vars} #{executable} #{args} 2>&1"
110
+
111
+ output = `#{command}`
112
+
113
+ File.open(output_path, 'w') do |file|
114
+ file.write command.sub(executable, name)
115
+ file.write "\n"
116
+
117
+ special_paths.each do |key, path|
118
+ output.gsub!(path, key)
119
+ end
120
+
121
+ file.write output
122
+ end
123
+
124
+ output
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,3 @@
1
+ module CLIntegracon
2
+ VERSION = "0.4.1"
3
+ end
@@ -0,0 +1,72 @@
1
+ CLIntegracon::Adapter::Bacon
2
+ coffee-maker
3
+ Brew recipes
4
+ without milk
5
+ - $ coffee-maker --no-milk
6
+ - BlackEye.brewed-coffee
7
+ - CaPheSuaDa.brewed-coffee
8
+ - Coffeemakerfile.yml
9
+ - execution_output.txt
10
+ - RedTux.brewed-coffee
11
+ - should not produce unexpected files [FAILED]
12
+ with honey as sweetner
13
+ - $ coffee-maker --sweetner=honey
14
+ - Affogato.brewed-coffee [FAILED]
15
+ - BlackEye.brewed-coffee [FAILED]
16
+ - Coffeemakerfile.yml
17
+ - execution_output.txt
18
+ - RedTux.brewed-coffee [FAILED]
19
+ - should not produce unexpected files
20
+ Get help
21
+ - $ coffee-maker --help
22
+ - execution_output.txt
23
+ - should not produce unexpected files
24
+
25
+ Bacon::Error: Unexpected files for coffeemaker_no_milk:
26
+ * Affogato.brewed-coffee
27
+ ./spec/bacon/spec_helper.rb:45
28
+ ./spec/bacon/spec_helper.rb:44
29
+ ./spec/bacon/spec_helper.rb:42
30
+ ./spec/bacon/spec_helper.rb:17
31
+ ./spec/bacon/spec_helper.rb:15
32
+ $GEM_HOME/bin/ruby_executable_hooks:15
33
+
34
+ Bacon::Error: File comparison error `Affogato.brewed-coffee` for coffeemaker_sweetner_honey:
35
+ --- DIFF -----------------------------------------------------------------------
36
+ class Affogato < BrewedCoffee
37
+ + @milk = true
38
+ @sweetner = honey
39
+ --- END ------------------------------------------------------------------------
40
+
41
+ ./spec/bacon/spec_helper.rb:49
42
+ ./spec/bacon/spec_helper.rb:48
43
+ ./spec/bacon/spec_helper.rb:42
44
+ ./spec/bacon/spec_helper.rb:17
45
+ ./spec/bacon/spec_helper.rb:15
46
+ $GEM_HOME/bin/ruby_executable_hooks:15
47
+
48
+ Bacon::Error: Missing file for coffeemaker_sweetner_honey:
49
+ * BlackEye.brewed-coffee
50
+ ./spec/bacon/spec_helper.rb:49
51
+ ./spec/bacon/spec_helper.rb:48
52
+ ./spec/bacon/spec_helper.rb:42
53
+ ./spec/bacon/spec_helper.rb:17
54
+ ./spec/bacon/spec_helper.rb:15
55
+ $GEM_HOME/bin/ruby_executable_hooks:15
56
+
57
+ Bacon::Error: File comparison error `RedTux.brewed-coffee` for coffeemaker_sweetner_honey:
58
+ --- DIFF -----------------------------------------------------------------------
59
+ class RedTux < BrewedCoffee
60
+ - @sweetner = sugar
61
+ + @milk = true
62
+ + @sweetner = honey
63
+ --- END ------------------------------------------------------------------------
64
+
65
+ ./spec/bacon/spec_helper.rb:49
66
+ ./spec/bacon/spec_helper.rb:48
67
+ ./spec/bacon/spec_helper.rb:42
68
+ ./spec/bacon/spec_helper.rb:17
69
+ ./spec/bacon/spec_helper.rb:15
70
+ $GEM_HOME/bin/ruby_executable_hooks:15
71
+
72
+ 17 specifications (27 requirements), 4 failures, 0 errors
@@ -0,0 +1,60 @@
1
+ require 'bacon'
2
+ require 'CLIntegracon'
3
+
4
+ ROOT = Pathname.new(File.expand_path('../../../', __FILE__))
5
+ BIN = ROOT + 'spec/fixtures/bin'
6
+
7
+ CLIntegracon.configure do |c|
8
+ c.context.spec_path = ROOT + 'spec/integration'
9
+ c.context.temp_path = ROOT + 'tmp/bacon_specs'
10
+
11
+ c.hook_into :bacon
12
+ end
13
+
14
+
15
+ describe CLIntegracon::Adapter::Bacon do
16
+
17
+ describe_cli 'coffee-maker' do
18
+
19
+ subject do |s|
20
+ s.name = 'coffee-maker'
21
+ s.executable = "bundle exec ruby #{BIN}/coffeemaker.rb"
22
+ s.environment_vars = {
23
+ 'COFFEE_MAKER_FILE' => 'Coffeemakerfile.yml'
24
+ }
25
+ s.default_args = [
26
+ '--verbose',
27
+ '--no-ansi'
28
+ ]
29
+ s.has_special_path ROOT.to_s, 'ROOT'
30
+ s.has_special_path `bundle show claide`.rstrip, 'CLAIDE_SRC'
31
+ end
32
+
33
+ context do |c|
34
+ c.ignores '.DS_Store'
35
+ c.ignores '.gitkeep'
36
+
37
+ c.has_special_handling_for 'execution_output.txt' do |path|
38
+ File.read(path).gsub(/:in `<main>'$/, '') # workaround different stack trace format by ruby-1.8.7
39
+ end
40
+ end
41
+
42
+ describe 'Brew recipes' do
43
+
44
+ describe 'without milk' do
45
+ behaves_like cli_spec('coffeemaker_no_milk', '--no-milk')
46
+ end
47
+
48
+ describe 'with honey as sweetner' do
49
+ behaves_like cli_spec('coffeemaker_sweetner_honey', '--sweetner=honey')
50
+ end
51
+
52
+ end
53
+
54
+ describe 'Get help' do
55
+ behaves_like cli_spec('coffeemaker_help', '--help')
56
+ end
57
+
58
+ end
59
+
60
+ end
@@ -0,0 +1,58 @@
1
+ #encoding: utf-8
2
+
3
+ require 'claide'
4
+ require 'colored'
5
+ require 'yaml'
6
+
7
+ # Don’t worry, this makes no sense, just an example
8
+ # command which modifies the file system.
9
+ class CoffeeMaker < CLAide::Command
10
+ self.description = 'Make delicious coffee from the comfort of your terminal.'
11
+
12
+ def self.options
13
+ [
14
+ ['--no-milk', 'Don’t add milk'],
15
+ ['--sweetner=[sugar|honey]', 'Use one of the available sweetners'],
16
+ ].concat(super)
17
+ end
18
+
19
+ def initialize(argv)
20
+ @add_milk = argv.flag?('milk', true)
21
+ @sweetner = argv.option('sweetner')
22
+ @config_file = ENV['COFFEE_MAKER_FILE'] || 'Coffeemakerfile'
23
+ super
24
+ end
25
+
26
+ def validate!
27
+ super
28
+ if @sweetner && !%w(sugar honey).include?(@sweetner)
29
+ help! "'#{@sweetner}' is not a valid sweetner."
30
+ end
31
+ end
32
+
33
+ def brew(recipe)
34
+ File.open recipe+'.brewed-coffee', 'w' do |f|
35
+ f.write "class #{recipe} < BrewedCoffee\n"
36
+ if @add_milk
37
+ f.write " @milk = true\n"
38
+ end
39
+ if @sweetner
40
+ f.write " @sweetner = #{@sweetner}\n"
41
+ end
42
+ end
43
+ end
44
+
45
+ def run
46
+ @config = YAML.load_file @config_file
47
+ if @config['recipes'] == nil
48
+ help! "Didn’t found any `recipes` in the Coffeemakerfile.yml."
49
+ end
50
+ @config['recipes'].each do |recipe|
51
+ puts "* Brewing #{recipe}"
52
+ brew(recipe)
53
+ end
54
+ puts '* Enjoy!'
55
+ end
56
+ end
57
+
58
+ CoffeeMaker.run(ARGV)
@@ -0,0 +1,23 @@
1
+ COFFEE_MAKER_FILE=Coffeemakerfile.yml coffee-maker --help --verbose --no-ansi 2>&1
2
+ Usage:
3
+
4
+ $ coffee-maker
5
+
6
+ Make delicious coffee from the comfort of your terminal.
7
+
8
+ Options:
9
+
10
+ --no-milk Don’t add milk
11
+ --sweetner=[sugar|honey] Use one of the available sweetners
12
+ --completion-script Print the auto-completion script
13
+ --version Show the version of the tool
14
+ --verbose Show more debugging information
15
+ --no-ansi Show output without ANSI codes
16
+ --help Show help banner of specified command
17
+
18
+ CLAIDE_SRC/lib/claide/command.rb:348:in `help!'
19
+ CLAIDE_SRC/lib/claide/command.rb:466:in `help!'
20
+ CLAIDE_SRC/lib/claide/command.rb:434:in `validate!'
21
+ ROOT/spec/fixtures/bin/coffeemaker.rb:27:in `validate!'
22
+ CLAIDE_SRC/lib/claide/command.rb:280:in `run'
23
+ ROOT/spec/fixtures/bin/coffeemaker.rb:58:in `<main>'
@@ -0,0 +1 @@
1
+ class BlackEye < BrewedCoffee
@@ -0,0 +1 @@
1
+ class CaPheSuaDa < BrewedCoffee
@@ -0,0 +1,5 @@
1
+ recipes:
2
+ - BlackEye
3
+ - Affogato
4
+ - CaPheSuaDa
5
+ - RedTux
@@ -0,0 +1 @@
1
+ class RedTux < BrewedCoffee
@@ -0,0 +1,6 @@
1
+ COFFEE_MAKER_FILE=Coffeemakerfile.yml coffee-maker --no-milk --verbose --no-ansi 2>&1
2
+ * Brewing BlackEye
3
+ * Brewing Affogato
4
+ * Brewing CaPheSuaDa
5
+ * Brewing RedTux
6
+ * Enjoy!