klipp 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -1
  3. data/.travis.yml +5 -0
  4. data/README.md +13 -26
  5. data/bin/klipp +1 -1
  6. data/klipp.gemspec +11 -6
  7. data/lib/klipp/configuration.rb +0 -4
  8. data/lib/klipp/creator.rb +78 -0
  9. data/lib/klipp/parameter_list.rb +3 -3
  10. data/lib/klipp/version.rb +1 -1
  11. data/lib/klipp.rb +148 -92
  12. data/lib/template/spec.rb +231 -0
  13. data/lib/template/token.rb +81 -0
  14. data/lib/template.rb +59 -0
  15. data/spec/fixtures/ambiguous-repo/Ambiguous/Ambiguous.klippspec +5 -0
  16. data/spec/fixtures/projects/Klippfile +26 -0
  17. data/spec/fixtures/projects/Klippfile-after-prepare +27 -0
  18. data/spec/fixtures/projects/Klippfile-ambiguous +1 -0
  19. data/spec/fixtures/projects/Klippfile-bad-ruby +3 -0
  20. data/spec/fixtures/projects/Klippfile-minimal +1 -0
  21. data/spec/fixtures/projects/Klippfile-unambiguous +1 -0
  22. data/spec/fixtures/template-repository/Ambiguous/Ambiguous.klippspec +5 -0
  23. data/spec/fixtures/template-repository/Another-Template/Another-Template.klippspec +20 -0
  24. data/spec/fixtures/template-repository/BadExample/BadExample.klippspec +35 -0
  25. data/spec/fixtures/template-repository/Empty/Empty.klippspec +20 -0
  26. data/spec/fixtures/template-repository/Example/.gitignore +10 -0
  27. data/spec/fixtures/template-repository/Example/Example.klippspec +40 -0
  28. data/spec/fixtures/template-repository/Example/Podfile +10 -0
  29. data/spec/fixtures/template-repository/Example/XXBLANKXX.hidden +10 -0
  30. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Config/Base.xcconfig +8 -0
  31. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Images/Default-568h@2x.png +0 -0
  32. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Images/Default.png +0 -0
  33. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Images/Default@2x.png +0 -0
  34. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Source/XXCLASS_PREFIXXXAppDelegate.h +13 -0
  35. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Source/XXCLASS_PREFIXXXAppDelegate.m +30 -0
  36. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Source/XXCLASS_PREFIXXXRootViewController.h +11 -0
  37. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/Source/XXCLASS_PREFIXXXRootViewController.m +30 -0
  38. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/XXPROJECT_TITLEXX-Info.plist +38 -0
  39. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/XXPROJECT_TITLEXX-Prefix.pch +14 -0
  40. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/en.lproj/Localizable.strings +1 -0
  41. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/main.m +17 -0
  42. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX/nl.lproj/Localizable.strings +1 -0
  43. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX.xcodeproj/project.pbxproj +466 -0
  44. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXX.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  45. data/spec/fixtures/template-repository/Example/XXPROJECT_IDXXTests/XXPROJECT_TITLEXXTests.m +22 -0
  46. data/spec/fixtures/template-repository/Interactive/Interactive.klippspec +15 -0
  47. data/spec/fixtures/template-repository/Interactive/XXSUBJECT_UNDER_TESTXXTests.m +15 -0
  48. data/spec/klipp/configuration_spec.rb +8 -0
  49. data/spec/klipp/creator_spec.rb +120 -0
  50. data/spec/klipp_spec.rb +80 -85
  51. data/spec/spec_helper.rb +8 -2
  52. data/spec/template/spec_spec.rb +225 -0
  53. data/spec/template/token_spec.rb +100 -0
  54. data/spec/template_spec.rb +82 -0
  55. metadata +118 -43
  56. data/lib/klipp/buffered_output.rb +0 -17
  57. data/lib/klipp/project.rb +0 -46
  58. data/lib/klipp/template.rb +0 -50
  59. data/lib/klipp/token.rb +0 -35
  60. data/spec/fixtures/klipps/Example.klippfile +0 -4
  61. data/spec/fixtures/klipps/ExcessiveExample.klippfile +0 -5
  62. data/spec/fixtures/klipps/Generated.klippfile +0 -11
  63. data/spec/fixtures/klipps/LackingExample.klippfile +0 -3
  64. data/spec/fixtures/klipps/MalformedExample.klippfile +0 -4
  65. data/spec/fixtures/klipps/single-token.yml +0 -5
  66. data/spec/fixtures/templates/Example/RegularFileWithContents.txt +0 -3
  67. data/spec/fixtures/templates/Example/XXCLASS_PREFIXXXPrefixedFile.txt +0 -3
  68. data/spec/fixtures/templates/Example/XXPROJECT_IDXX/BinaryFile.png +0 -0
  69. data/spec/fixtures/templates/Example/XXPROJECT_IDXX/XXCLASS_PREFIXXXPrefixedFileInDirectory.txt +0 -3
  70. data/spec/fixtures/templates/Example.yml +0 -29
  71. data/spec/klipp/project_spec.rb +0 -46
  72. data/spec/klipp/template_spec.rb +0 -80
  73. data/spec/klipp/token_spec.rb +0 -86
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ad411833795ad014a927e4dc6851f5d4c2630d6
4
- data.tar.gz: 85ae4b599bf421be5ec49b50ff4f9b7bc699585b
3
+ metadata.gz: 65f854ee8a77a48f90783f08804f8e9f98d854fd
4
+ data.tar.gz: b361e5e190a5cd52039de0f5fd470ca193808944
5
5
  SHA512:
6
- metadata.gz: d3ef430e9e4110b425a3da45dfef5ab577e65d7c24f73aac7ca6c32c8c97beb4deb5b9956731bf9affd09d50788b5b090724633fa5862ff51fb89a2643dfc350
7
- data.tar.gz: df73b6338e8583b51dc78a855b532eb5e429eada147258db201b3b4b12d3e4b3c7a71fe75e267e3ec36221c985a727d23d032a1783599fd1c5c6bf54fd234d4b
6
+ metadata.gz: 78cbc60461c33266df988e6786016ff039f8c3a4d0aec50dccf0541568cc7cac322459f649ba351f63db223a604c960784ecdff51681a6912e239649832925b3
7
+ data.tar.gz: de1ddee465b7b099eb8196c8286dfc38445aad486b06d831d91e4e4fa765fe315ce4a6c3bf9aacc66665e53770cf82746e2a2dc50df593b719b068eaf88c0e32
data/.gitignore CHANGED
@@ -15,4 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
- .idea
18
+ .idea
19
+ Sandbox
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+
5
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,7 +1,9 @@
1
- # Klipp
2
- ## Xcode templates for the rest of us.
1
+ # Klipp [![Build Status](https://travis-ci.org/epologee/klipp.png)](https://travis-ci.org/epologee/klipp) [![Coverage Status](https://coveralls.io/repos/epologee/klipp/badge.png)](https://coveralls.io/r/epologee/klipp)
2
+ ## Code templates for the rest of us.
3
3
 
4
- Klipp is a command line gem for creating new (Xcode) projects from existing templates. Unlike Apple's private plist-based templating system, Klipp takes an existing Xcode project and creates a new project by copying and modifying an existing template project by your own specifications.
4
+ Klipp is a ruby gem with a command line interface for creating new programming projects from existing templates. It was originally designed to create Xcode projects. However, there are no Apple or Xcode specific features in Klipp, so you can use it for pretty much any textfile-and-directory-based template.
5
+
6
+ When compared to Xcode's plist-based templating system, Klipp takes an existing Xcode project and creates a new project by copying and modifying an existing template project by your own specifications.
5
7
 
6
8
  ## Installation
7
9
 
@@ -13,31 +15,16 @@ Execute and read the usage instructions:
13
15
 
14
16
  $ klipp
15
17
 
16
- ## Usage
17
-
18
- Klipp creates a template repository in your home directory, at ~/.klipp/templates
19
- A template consists of a directory and an accompanying Yaml file, e.g.:
20
-
21
- TemplateA
22
- TemplateA.yml
23
-
24
- Once you have templates like these present, you can prepare a new instance of that project by executing:
25
-
26
- $ klipp prepare TemplateA
27
-
28
- This will create a TemplateA.klippfile in your current directory, for you to edit with your favorite text editor.
29
- From there, customize your project and when happy with the results, run:
30
-
31
- $ klipp create
18
+ ## CLI under construction ...
32
19
 
33
- This will create a new directory called TemplateA, that contains your new project.
34
-
35
- ## Known issues
20
+ Klipp is still in the early development stage. When 0.1 ships, the CLI will feature:
36
21
 
37
- * Creating templates is done manually, this will be automated
38
- * Errors while parsing the .klippfile are not yet handled gracefully
39
- * Highline support for on-the-fly creation of new projects is not yet enabled
40
- * The root of newly created projects carries the same name as the template, this will be adjustable.
22
+ * `klipp repo add <repo-name> [<repo-url>]` - git init [or clone] template repositories in the `~/.klipp` directory
23
+ * `klipp template spec <template-name>` - creates a new template specificiation called `<template-name>.klippspec`, for you to configure your template's properties.
24
+ * `klipp template push <repo-name>` - push a new template to one of your template repositories.
25
+ * `klipp template list [<repo-name>]` - list all available templates on your machine [per repository]
26
+ * `klipp prepare <template-name>` - prepare the creation of files from a new template, by authoring a `Klippfile`
27
+ * `klipp create [<template-name>]` - create files based on the prepared `Klippfile` [or interactively from the terminal].
41
28
 
42
29
  ## Contributing
43
30
 
data/bin/klipp CHANGED
@@ -3,4 +3,4 @@
3
3
  require 'klipp'
4
4
 
5
5
  Klipp::Configuration.auto_create_dirs = true
6
- Klipp.route(*ARGV)
6
+ exit Klipp.route(*ARGV)
data/klipp.gemspec CHANGED
@@ -13,14 +13,19 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = 'https://github.com/epologee/klipp'
14
14
  spec.license = 'MIT'
15
15
 
16
- spec.files = `git ls-files`.split($/)
16
+ spec.files = `git ls-files`.split($/).map
17
+ #do |f|
18
+ # f unless f.include?('spec/fixtures') || f.include?("_spec.rb")
19
+ #end
17
20
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
21
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
22
  spec.require_paths = %w(lib)
20
23
 
21
- spec.add_development_dependency 'bundler', '~> 1.3'
22
- spec.add_development_dependency 'rake'
23
- spec.add_development_dependency 'highline'
24
- spec.add_development_dependency 'ptools'
25
- spec.add_development_dependency 'colored'
24
+ spec.add_runtime_dependency 'bundler', '~> 1.3'
25
+ spec.add_runtime_dependency 'rake'
26
+ spec.add_runtime_dependency 'ptools'
27
+ spec.add_runtime_dependency 'formatador'
28
+ spec.add_runtime_dependency 'colorize'
29
+ spec.add_runtime_dependency 'grit'
30
+ spec.add_runtime_dependency 'highline'
26
31
  end
@@ -22,10 +22,6 @@ module Klipp
22
22
  auto_create File.join(Dir.home, '.klipp')
23
23
  end
24
24
 
25
- def self.templates_dir
26
- auto_create File.join(root_dir, 'templates')
27
- end
28
-
29
25
  end
30
26
 
31
27
  end
@@ -0,0 +1,78 @@
1
+ module Klipp
2
+
3
+ class Creator
4
+ attr_reader :identifier, :tokens
5
+
6
+ def self.from_file(path)
7
+ raise "Klippfile not found in directory #{File.dirname path}. Run `klipp prepare`." unless File.exists? path
8
+ string = IO.read path
9
+ creator = Klipp::Creator.new
10
+ creator.eval_string(string, path)
11
+ end
12
+
13
+ def self.from_user_input(template_identifier, highline)
14
+ creator = Klipp::Creator.new
15
+ creator.ask_user_input(template_identifier, highline)
16
+ end
17
+
18
+ def initialize
19
+ @tokens = Hash.new
20
+ end
21
+
22
+ def eval_string(string, path)
23
+ begin
24
+ eval(string, nil, path)
25
+ rescue Exception => e
26
+ raise "Error evaluating klippfile: #{File.basename(path)}: #{e.message}\n #{e.backtrace.join("\n ")}"
27
+ end
28
+ validate
29
+ end
30
+
31
+ def ask_user_input(identifier, highline = HighLine.new)
32
+ @identifier = identifier
33
+ spec_path = Template::Spec.spec_path_for_identifier(identifier)
34
+ template = Template::Spec.from_file(spec_path)
35
+ template.each do |name, token|
36
+ self.tokens[name] = highline.ask("#{token.comment}?") { |q|
37
+ q.validate = token.validation if token.validation
38
+ q.responses[:not_valid] = token.validation_hint if token.validation_hint
39
+ } unless token.hidden
40
+ end
41
+ validate
42
+ end
43
+
44
+ def validate
45
+ msg = 'Klippfile invalid: '
46
+ invalidate msg+'missing name' unless @identifier && @identifier.length > 0
47
+ matching_specs = Template::Spec.specs_matching_identifier(@identifier)
48
+
49
+ case
50
+ when matching_specs.count == 0
51
+ msg += "Unknown template name `#{@identifier}`. "
52
+ msg += "Run `klipp template list` to see your options."
53
+ invalidate msg+msg
54
+ when matching_specs.count > 1
55
+ msg += "Found multiple templates named `#{@identifier}`. "
56
+ msg += "Use a full template identifier to pick one. "
57
+ msg += "Run `klipp template list` to see your options."
58
+ hint msg+msg
59
+ else
60
+ self
61
+ end
62
+ end
63
+
64
+ def invalidate(message)
65
+ raise message
66
+ end
67
+
68
+ def hint(message)
69
+ raise Klipp::Hint.new(message)
70
+ end
71
+
72
+ def create(template_identifier, &config)
73
+ @identifier = template_identifier
74
+ config.yield(@tokens) if block_given?
75
+ end
76
+ end
77
+
78
+ end
@@ -8,9 +8,9 @@ module Klipp
8
8
  self - options
9
9
  end
10
10
 
11
- #def splice_option(name)
12
- # !!delete(name)
13
- #end
11
+ def splice_option(name)
12
+ !!delete(name)
13
+ end
14
14
 
15
15
  def shift_argument
16
16
  (arg = arguments[0]) && delete(arg)
data/lib/klipp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Klipp
2
- VERSION = "0.0.1"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/klipp.rb CHANGED
@@ -1,135 +1,191 @@
1
- require 'klipp/buffered_output'
2
- require 'klipp/version'
1
+ require 'ptools'
2
+ require 'formatador'
3
+ require 'colorize'
4
+ require 'fileutils'
5
+ require 'grit'
6
+ require 'highline/import'
7
+
8
+ require 'template'
3
9
  require 'klipp/configuration'
4
- require 'klipp/token'
5
- require 'klipp/template'
10
+ require 'klipp/version'
6
11
  require 'klipp/parameter_list'
7
- require 'klipp/project'
8
- require 'colorize'
12
+ require 'klipp/creator'
9
13
 
10
14
  module Klipp
11
- extend BufferedOutput::ClassMethods
12
15
 
13
- def self.display_exception exception
14
- if exception.is_a? HelpRequest
15
- help = exception
16
- else
17
- help = HelpRequest.new exception.message, true
18
- help.set_backtrace(exception.backtrace)
19
- end
16
+ class Hint < StandardError
17
+ end
18
+
19
+ def self.env
20
+ @@env ||= StringInquirer.new('prod')
21
+ end
20
22
 
21
- buffer_puts help.message
22
- exit help.exit_status
23
+ def self.env=(env)
24
+ @@env = env
23
25
  end
24
26
 
25
27
  def self.route(*argv)
26
- @params = Klipp::ParameterList.new(argv)
27
- command = @params.shift_argument
28
+ params = Klipp::ParameterList.new(argv)
29
+ command = params.shift_argument;
30
+ commands = {
31
+ prepare: lambda { cli_prepare(params) },
32
+ create: lambda { cli_create(params) },
33
+ template: lambda { Template.route(*params) }
34
+ }
28
35
  case command
29
- when 'version'
30
- version
31
- when 'list'
32
- list
33
- when 'prepare'
34
- prepare @params.first
35
- when 'create'
36
- create @params.first
37
36
  when nil
38
- raise HelpRequest.new('Use one of the commands below to start with klipp.', false, true)
37
+ raise Klipp::Hint.new "Add a command to `klipp [#{commands.keys.join('|')}]`"
39
38
  else
40
- raise "Unknown command: #{command}"
39
+ if commands[command.to_sym]
40
+ commands[command.to_sym].call
41
+ else
42
+ raise "Unknown command `klipp #{command}`"
43
+ end
41
44
  end
42
-
45
+ 0 # exit code
43
46
  rescue Exception => e
44
- display_exception e
47
+ case e
48
+ when Klipp::Hint
49
+ Formatador.display_line("[yellow][?] #{e.message}[/]")
50
+ else
51
+ Formatador.display_line("[red][!] #{e.message}[/]")
52
+ Formatador.display_line(e.backtrace[0..10].join("\n"))
53
+ end
54
+ 1 # exit code
45
55
  end
46
56
 
47
- def self.version
48
- buffer_puts Klipp::VERSION
49
- end
57
+ def self.cli_prepare(params=[])
58
+ params = Klipp::ParameterList.new(params)
59
+ template = params.shift_argument
60
+ raise Klipp::Hint.new("Add a template name to `klipp prepare [template]`. Use `klipp template list` to see your options.") unless template
50
61
 
51
- def self.list
52
- files = template_files
62
+ spec = Template::Spec.from_file Template::Spec.spec_path_for_identifier(template)
63
+ filename = 'Klippfile'
53
64
 
54
- raise "No templates found. Create a template directory and .yml file in #{Klipp::Configuration.templates_dir}" unless files.length > 0
65
+ force = params.splice_option('-f')
66
+ will_overwrite = File.exists?(filename) && force
55
67
 
56
- buffer_puts("Available templates for use with #{'klipp prepare'.yellow} or #{'klipp create'.yellow}:\n\n")
57
- files.each do |file|
58
- buffer_puts(" * #{File.basename(file, '.*').green}")
59
- end
60
- end
68
+ raise "#{filename} already exists, not overwriting. Use -f to force overwriting." if File.exists?(filename) && !force
69
+
70
+ File.write('Klippfile', spec.klippfile)
61
71
 
62
- def self.prepare(template_name)
63
- raise HelpRequest.new 'Add a template name to the `prepare` command.' unless template_name
72
+ Formatador.display_line("[green][√] Prepared #{filename} #{'again' if will_overwrite}.[/]")
64
73
 
65
- template = Klipp::Template.new(Klipp::Configuration.templates_dir, template_name)
66
- raise "#{template.klippfile} already exists. Delete it if you want to prepare a new template." if File.exists? template.klippfile
67
- IO.write(template.klippfile, template.generated_klippfile)
74
+ capture_stdout {
75
+ `open -a TextMate #{filename} 2>&1` if File.exists?(filename)
76
+ }
77
+
78
+ if $? && $?.exitstatus > 0
79
+ `open -t #{filename}` if File.exists?(filename)
80
+ end
68
81
  end
69
82
 
70
- def self.create(template_name)
71
- if template_name
72
- klippfile = File.join(Dir.pwd, "#{template_name}.klippfile")
83
+ def self.cli_create(params, highline = nil)
84
+ params = Klipp::ParameterList.new(params)
85
+ if (interactive_identifier = params.shift_argument)
86
+ creator = Klipp::Creator.from_user_input(interactive_identifier, highline)
87
+ puts()
73
88
  else
74
- klippfile = Dir.glob(File.join(Dir.pwd, '*.klippfile')).first
75
- template_name = File.basename(klippfile, File.extname(klippfile)) if klippfile
89
+ creator = Klipp::Creator.from_file File.join(Dir.pwd, 'Klippfile')
90
+ end
91
+ spec_path = Template::Spec.spec_path_for_identifier creator.identifier
92
+ spec = Template::Spec.from_file spec_path
93
+ spec.set_token_values(creator.tokens, params.splice_option('-v'))
94
+
95
+ block_actions = spec.block_actions_under_git && git_repository?
96
+ if spec.pre_actions.count > 0
97
+ if block_actions
98
+ Formatador.display_line("[yellow][i][/] Git repository found, not running pre-actions (see .klippspec).")
99
+ puts()
100
+ else
101
+ run_actions(spec.pre_actions) if Klipp.env.prod?
102
+ Formatador.display_line("[green][√] Pre-actions complete.[/]")
103
+ puts()
104
+ end
76
105
  end
77
106
 
78
- template = Klipp::Template.new(Klipp::Configuration.templates_dir, template_name)
107
+ force = params.splice_option('-f')
79
108
 
80
- if klippfile
81
- # load token values from klippfile
82
- template.load_klippfile klippfile
83
- elsif template_name
84
- # ask for token values with highline
85
- raise "Direct user input not yet supported. Use #{'klipp prepare'.yellow} to prepare a .klippfile"
86
- else
87
- raise "Add a template name to the `create` command, or use #{'klipp prepare'.yellow} to prepare a .klippfile"
109
+ source_dir = File.dirname(Template::Spec.spec_path_for_identifier creator.identifier)
110
+ target_dir = Dir.pwd
111
+
112
+ source_files = Dir.glob(File.join(source_dir, '**', '*'), File::FNM_DOTMATCH).reject { |f| f == spec_path }
113
+
114
+ result = source_files.map do |source_file|
115
+ spec.transfer_file source_file, spec.target_file(source_dir, source_file, target_dir), force
88
116
  end
89
117
 
90
- project = Klipp::Project.new(template)
91
- project.create
92
- end
118
+ verbose = params.splice_option '-v'
93
119
 
94
- private
120
+ Formatador.display_line("[green][√] Creation completed using template #{Template::Spec.expand_identifier creator.identifier}. #{'Run `klipp create -v` to see what files were created.' unless verbose}[/]")
121
+ puts()
95
122
 
96
- def self.template_files
97
- Dir.glob File.join(Klipp::Configuration.templates_dir, '*.yml')
98
- end
123
+ if (verbose)
124
+ strip = File.dirname(Dir.pwd)+File::SEPARATOR
125
+ result.each { |r| Formatador.display_line(r.gsub(strip, '')) unless File.directory? r }
126
+ puts()
127
+ end
99
128
 
100
- end
129
+ if spec.post_actions.count > 0
130
+ if block_actions
131
+ Formatador.display_line("[yellow][i][/] Git repository found, not running post-actions (see .klippspec).")
132
+ puts()
133
+ else
134
+ run_actions(spec.post_actions) if Klipp.env.prod?
135
+ Formatador.display_line("[green][√] Post-actions complete.[/]")
136
+ puts()
137
+ end
138
+ end
101
139
 
102
- class HelpRequest < StandardError
103
- def initialize(msg, unknown=false, show_title=false)
104
- @unknown = unknown
105
- @show_title = show_title
106
- super(msg)
140
+ Formatador.display_line("[green][√] Done.[/]")
107
141
  end
108
142
 
109
- def message
110
- if @unknown
111
- "[!] #{super.to_s}".red+"\n\n#{commands}\n\n#{self.backtrace.join("\n")}"
112
- else
113
- "#{@show_title ? title+"\n\n" : ''}"+"[?] #{super.to_s}".yellow+"\n\n#{commands}"
114
- end
143
+ def self.git_repository?
144
+ `git rev-parse --is-inside-work-tree 2>&1`.match /true/
115
145
  end
116
146
 
117
- def title
118
- "\033[1mKlipp\033[22m, Xcode templates for the rest of us. Version: #{Klipp::VERSION}"
147
+ def self.run_actions(actions)
148
+ count = actions.count()
149
+ puts()
150
+ actions.each do |action|
151
+ Formatador.display_line("[yellow][i][/] Running `#{action}`...")
152
+ puts()
153
+ system(action) if Klipp.env.prod?
154
+ puts()
155
+ #IO.popen(action, :err=>[:child, :out]) { |f| puts ' '+f.read.gsub("\n", "\n ") }
156
+ raise "Error running action `#{action}`." if $? && $?.exitstatus > 0
157
+ end
119
158
  end
159
+ end
120
160
 
121
- def commands
122
- commands = [
123
- version: 'Display the Klipp version number.',
124
- list: "List all available klipp templates in #{Klipp::Configuration.templates_dir}",
125
- prepare: 'Prepare a .klippfile to edit in your favorite text editor.',
126
- create: 'Create a project based on the template name or .klippfile in the current directory'
127
- ]
128
- command_list = commands.map { |cmd| cmd.map { |key, summary| " * klipp #{key.to_s.ljust(10).green} #{summary}" } }.join("\n")
129
- "Commands:\n\n#{command_list}"
161
+ class StringInquirer < String
162
+ def method_missing(method_name, *arguments)
163
+ if method_name.to_s[-1,1] == '?'
164
+ self == method_name.to_s[0..-2]
165
+ else
166
+ super
167
+ end
130
168
  end
169
+ end
131
170
 
132
- def exit_status
133
- @unknown ? 2 : 1
171
+ def capture_stdout
172
+ old_stdout = STDOUT.clone
173
+ pipe_r, pipe_w = IO.pipe
174
+ pipe_r.sync = true
175
+ output = ''
176
+ reader = Thread.new do
177
+ begin
178
+ loop do
179
+ output << pipe_r.readpartial(1024)
180
+ end
181
+ rescue EOFError
182
+ end
134
183
  end
184
+ STDOUT.reopen pipe_w
185
+ yield
186
+ ensure
187
+ STDOUT.reopen old_stdout
188
+ pipe_w.close
189
+ reader.join
190
+ return output
135
191
  end