rcli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +193 -0
  3. data/README.rdoc +194 -0
  4. data/Rakefile +61 -0
  5. data/bin/rcli +12 -0
  6. data/lib/commands/compile.rb +15 -0
  7. data/lib/commands/debug.rb +86 -0
  8. data/lib/commands/edit.rb +34 -0
  9. data/lib/commands/generate.rb +43 -0
  10. data/lib/commands/help.rb +47 -0
  11. data/lib/commands/install.rb +86 -0
  12. data/lib/commands/list.rb +28 -0
  13. data/lib/commands/uninstall.rb +36 -0
  14. data/lib/commands/version.rb +11 -0
  15. data/lib/core/actions/create_file.rb +106 -0
  16. data/lib/core/actions/empty_directory.rb +88 -0
  17. data/lib/core/actions/file_binary_read.rb +9 -0
  18. data/lib/core/actions.rb +9 -0
  19. data/lib/core/command.rb +137 -0
  20. data/lib/core/commander.rb +48 -0
  21. data/lib/core/console.rb +5 -0
  22. data/lib/core/global_functions.rb +16 -0
  23. data/lib/core/shared/rcli_installation.rb +9 -0
  24. data/lib/core/thor_actions/create_file.rb +100 -0
  25. data/lib/core/thor_actions/directory.rb +89 -0
  26. data/lib/core/thor_actions/empty_directory.rb +134 -0
  27. data/lib/core/thor_actions/file_binary_read.rb +9 -0
  28. data/lib/core/thor_actions/file_manipulation.rb +223 -0
  29. data/lib/core/thor_actions/inject_into_file.rb +102 -0
  30. data/lib/core/thor_actions.rb +302 -0
  31. data/lib/core/traceable_factory.rb +20 -0
  32. data/lib/core/traceable_object.rb +45 -0
  33. data/lib/core/tracer.rb +23 -0
  34. data/lib/rcli.rb +65 -0
  35. data/lib/templates/new_app/RCLIAPPNAME.rb +9 -0
  36. data/lib/templates/new_app/lib/commands/default.rb +12 -0
  37. data/lib/templates/new_app/lib/commands/version.rb +6 -0
  38. data/lib/vendor/mainline/lib/trollop.rb +782 -0
  39. data/lib/vendor/mainline/test/test_trollop.rb +1094 -0
  40. data/lib/vendor/trollop.rb +782 -0
  41. data/test/helper.rb +10 -0
  42. data/test/test_rcli-gem.rb +7 -0
  43. metadata +137 -0
@@ -0,0 +1,302 @@
1
+ require 'fileutils'
2
+ require 'uri'
3
+ require 'core/actions/file_binary_read'
4
+
5
+ Dir[File.join(Rcli::GEM_LIB, "actions", "*.rb")].each do |action|
6
+ require action
7
+ end
8
+
9
+ class Rcli
10
+ module Actions
11
+ attr_accessor :behavior
12
+
13
+ def self.included(base) #:nodoc:
14
+ base.extend ClassMethods
15
+ end
16
+
17
+ module ClassMethods
18
+ # Hold source paths for one Thor instance. source_paths_for_search is the
19
+ # method responsible to gather source_paths from this current class,
20
+ # inherited paths and the source root.
21
+ #
22
+ def source_paths
23
+ @_source_paths ||= []
24
+ end
25
+
26
+ # Stores and return the source root for this class
27
+ def source_root(path=nil)
28
+ @_source_root = path if path
29
+ @_source_root
30
+ end
31
+
32
+ # Returns the source paths in the following order:
33
+ #
34
+ # 1) This class source paths
35
+ # 2) Source root
36
+ # 3) Parents source paths
37
+ #
38
+ def source_paths_for_search
39
+ paths = []
40
+ paths += self.source_paths
41
+ paths << self.source_root if self.source_root
42
+ paths += from_superclass(:source_paths, [])
43
+ paths
44
+ end
45
+
46
+ # Add runtime options that help actions execution.
47
+ #
48
+ def add_runtime_options!
49
+ class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
50
+ :desc => "Overwrite files that already exist"
51
+
52
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
53
+ :desc => "Run but do not make any changes"
54
+
55
+ class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
56
+ :desc => "Supress status output"
57
+
58
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
59
+ :desc => "Skip files that already exist"
60
+ end
61
+ end
62
+
63
+ # Extends initializer to add more configuration options.
64
+ #
65
+ # ==== Configuration
66
+ # behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
67
+ # It also accepts :force, :skip and :pretend to set the behavior
68
+ # and the respective option.
69
+ #
70
+ # destination_root<String>:: The root directory needed for some actions.
71
+ #
72
+ # def initialize(args=[], options={}, config={})
73
+ # pp args
74
+ # puts "asdfasdf"
75
+ # pp options
76
+ # puts "asdfasdf"
77
+ # pp config
78
+ # puts "asdfasdf"
79
+ # self.behavior = case config[:behavior].to_s
80
+ # when "force", "skip"
81
+ # _cleanup_options_and_set(options, config[:behavior])
82
+ # :invoke
83
+ # when "revoke"
84
+ # :revoke
85
+ # else
86
+ # :invoke
87
+ # end
88
+ #
89
+ # super
90
+ # self.destination_root = config[:destination_root]
91
+ # end
92
+
93
+ # Wraps an action object and call it accordingly to the thor class behavior.
94
+ #
95
+ def action(instance) #:nodoc:
96
+ if behavior == :revoke
97
+ instance.revoke!
98
+ else
99
+ instance.invoke!
100
+ end
101
+ end
102
+
103
+ # Returns the root for this thor class (also aliased as destination root).
104
+ #
105
+ def destination_root
106
+ @destination_stack.last
107
+ end
108
+
109
+ # Sets the root for this thor class. Relatives path are added to the
110
+ # directory where the script was invoked and expanded.
111
+ #
112
+ def destination_root=(root)
113
+ @destination_stack ||= []
114
+ @destination_stack[0] = File.expand_path(root || '')
115
+ end
116
+
117
+ # Returns the given path relative to the absolute root (ie, root where
118
+ # the script started).
119
+ #
120
+ def relative_to_original_destination_root(path, remove_dot=true)
121
+ path = path.gsub(@destination_stack[0], '.')
122
+ remove_dot ? (path[2..-1] || '') : path
123
+ end
124
+
125
+ # Holds source paths in instance so they can be manipulated.
126
+ #
127
+ def source_paths
128
+ @source_paths ||= self.class.source_paths_for_search
129
+ end
130
+
131
+ # Receives a file or directory and search for it in the source paths.
132
+ #
133
+ def find_in_source_paths(file)
134
+ relative_root = relative_to_original_destination_root(destination_root, false)
135
+
136
+ source_paths.each do |source|
137
+ source_file = File.expand_path(file, File.join(source, relative_root))
138
+ return source_file if File.exists?(source_file)
139
+ end
140
+
141
+ message = "Could not find #{file.inspect} in any of your source paths. "
142
+
143
+ unless self.class.source_root
144
+ message << "Please invoke #{self.class.name}.source_root(PATH) with the PATH containing your templates. "
145
+ end
146
+
147
+ if source_paths.empty?
148
+ message << "Currently you have no source paths."
149
+ else
150
+ message << "Your current source paths are: \n#{source_paths.join("\n")}"
151
+ end
152
+
153
+ raise Error, message
154
+ end
155
+
156
+ # Do something in the root or on a provided subfolder. If a relative path
157
+ # is given it's referenced from the current root. The full path is yielded
158
+ # to the block you provide. The path is set back to the previous path when
159
+ # the method exits.
160
+ #
161
+ # ==== Parameters
162
+ # dir<String>:: the directory to move to.
163
+ # config<Hash>:: give :verbose => true to log and use padding.
164
+ #
165
+ def inside(dir='', config={}, &block)
166
+ verbose = config.fetch(:verbose, false)
167
+
168
+ say_status :inside, dir, verbose
169
+ shell.padding += 1 if verbose
170
+ @destination_stack.push File.expand_path(dir, destination_root)
171
+
172
+ FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
173
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
174
+
175
+ @destination_stack.pop
176
+ shell.padding -= 1 if verbose
177
+ end
178
+
179
+ # Goes to the root and execute the given block.
180
+ #
181
+ def in_root
182
+ inside(@destination_stack.first) { yield }
183
+ end
184
+
185
+ # Loads an external file and execute it in the instance binding.
186
+ #
187
+ # ==== Parameters
188
+ # path<String>:: The path to the file to execute. Can be a web address or
189
+ # a relative path from the source root.
190
+ #
191
+ # ==== Examples
192
+ #
193
+ # apply "http://gist.github.com/103208"
194
+ #
195
+ # apply "recipes/jquery.rb"
196
+ #
197
+ def apply(path, config={})
198
+ verbose = config.fetch(:verbose, true)
199
+ path = find_in_source_paths(path) unless path =~ /^http\:\/\//
200
+
201
+ say_status :apply, path, verbose
202
+ shell.padding += 1 if verbose
203
+
204
+ if URI(path).is_a?(URI::HTTP)
205
+ contents = open(path, "Accept" => "application/x-thor-template") {|io| io.read }
206
+ else
207
+ contents = open(path) {|io| io.read }
208
+ end
209
+
210
+ instance_eval(contents, path)
211
+ shell.padding -= 1 if verbose
212
+ end
213
+
214
+ # Executes a command returning the contents of the command.
215
+ #
216
+ # ==== Parameters
217
+ # command<String>:: the command to be executed.
218
+ # config<Hash>:: give :verbose => false to not log the status. Specify :with
219
+ # to append an executable to command executation.
220
+ #
221
+ # ==== Example
222
+ #
223
+ # inside('vendor') do
224
+ # run('ln -s ~/edge rails')
225
+ # end
226
+ #
227
+ def run(command, config={})
228
+ return unless behavior == :invoke
229
+
230
+ destination = relative_to_original_destination_root(destination_root, false)
231
+ desc = "#{command} from #{destination.inspect}"
232
+
233
+ if config[:with]
234
+ desc = "#{File.basename(config[:with].to_s)} #{desc}"
235
+ command = "#{config[:with]} #{command}"
236
+ end
237
+
238
+ say_status :run, desc, config.fetch(:verbose, true)
239
+ `#{command}` unless options[:pretend]
240
+ end
241
+
242
+ # Executes a ruby script (taking into account WIN32 platform quirks).
243
+ #
244
+ # ==== Parameters
245
+ # command<String>:: the command to be executed.
246
+ # config<Hash>:: give :verbose => false to not log the status.
247
+ #
248
+ def run_ruby_script(command, config={})
249
+ return unless behavior == :invoke
250
+ run command, config.merge(:with => Thor::Util.ruby_command)
251
+ end
252
+
253
+ # Run a thor command. A hash of options can be given and it's converted to
254
+ # switches.
255
+ #
256
+ # ==== Parameters
257
+ # task<String>:: the task to be invoked
258
+ # args<Array>:: arguments to the task
259
+ # config<Hash>:: give :verbose => false to not log the status. Other options
260
+ # are given as parameter to Thor.
261
+ #
262
+ # ==== Examples
263
+ #
264
+ # thor :install, "http://gist.github.com/103208"
265
+ # #=> thor install http://gist.github.com/103208
266
+ #
267
+ # thor :list, :all => true, :substring => 'rails'
268
+ # #=> thor list --all --substring=rails
269
+ #
270
+ def thor(task, *args)
271
+ config = args.last.is_a?(Hash) ? args.pop : {}
272
+ verbose = config.key?(:verbose) ? config.delete(:verbose) : true
273
+ pretend = config.key?(:pretend) ? config.delete(:pretend) : false
274
+
275
+ args.unshift task
276
+ args.push Thor::Options.to_switches(config)
277
+ command = args.join(' ').strip
278
+
279
+ run command, :with => :thor, :verbose => verbose, :pretend => pretend
280
+ end
281
+
282
+ protected
283
+
284
+ # Allow current root to be shared between invocations.
285
+ #
286
+ def _shared_configuration #:nodoc:
287
+ super.merge!(:destination_root => self.destination_root)
288
+ end
289
+
290
+ def _cleanup_options_and_set(options, key) #:nodoc:
291
+ case options
292
+ when Array
293
+ %w(--force -f --skip -s).each { |i| options.delete(i) }
294
+ options << "--#{key}"
295
+ when Hash
296
+ [:force, :skip, "force", "skip"].each { |i| options.delete(i) }
297
+ options.merge!(key => true)
298
+ end
299
+ end
300
+
301
+ end
302
+ end
@@ -0,0 +1,20 @@
1
+ require 'core/traceable_object'
2
+
3
+ class TraceableFactory
4
+
5
+ def self.createTraceableObject( className, *args )
6
+
7
+ TraceableObject.before_init(className) if Rcli.trace_app
8
+
9
+ obj = Object.const_get( className ).new(*args)
10
+
11
+ TraceableObject.after_init(className) if Rcli.trace_app
12
+
13
+ if Rcli.trace_app
14
+ return TraceableObject.new(obj,*args)
15
+ else
16
+ return obj
17
+ end
18
+ end
19
+
20
+ end
@@ -0,0 +1,45 @@
1
+ class TraceableObject
2
+
3
+ def initialize(obj)
4
+ @obj = obj
5
+ end
6
+
7
+ def self.before_init(classname)
8
+ puts "-- s - #{classname}.initialize() ---"
9
+ end
10
+
11
+ def self.after_init(classname)
12
+ puts "-- f - #{classname}.initialize() ---"
13
+
14
+ end
15
+
16
+ def before_trace(sym)
17
+ puts "-- s - #{@obj.class}.#{sym}() ---"
18
+ end
19
+
20
+ def after_trace(sym)
21
+ puts "-- f - #{@obj.class}.#{sym}() ---"
22
+ end
23
+
24
+ def self.before_trace(className, sym)
25
+ puts "-- s - #{className}::#{sym}() ---"
26
+ end
27
+
28
+ def self.after_trace(className, sym)
29
+ puts "-- f - #{className}::#{sym}() ---"
30
+ end
31
+
32
+ def method_missing(sym, *args, &block)
33
+ before_trace(sym)
34
+ @obj.send sym, *args, &block
35
+ after_trace(sym)
36
+ end
37
+
38
+ def self.call_class_method(className, sym, *args, &block)
39
+ self.before_trace(className, sym) if Rcli.trace_app
40
+ retval = Object.const_get( className ).send sym, *args, &block
41
+ self.after_trace(className, sym) if Rcli.trace_app
42
+ retval
43
+ end
44
+
45
+ end
@@ -0,0 +1,23 @@
1
+ def s
2
+ trace = ''
3
+ m = caller[0][/`([^']*)'/, 1]
4
+ if "#{self.class}" == "Class"
5
+ trace = "-- s - #{self}::#{m}() --- "
6
+ else
7
+ trace = "-- s - #{self.class}.#{m}() --- "
8
+ end
9
+
10
+ puts trace if TRACE_APP
11
+ end
12
+
13
+ def f
14
+ trace = ''
15
+ m = caller[0][/`([^']*)'/, 1]
16
+ if "#{self.class}" == "Class"
17
+ trace = "-- f - #{self}::#{m}() --- "
18
+ else
19
+ trace = "-- f - #{self.class}.#{m}() --- "
20
+ end
21
+
22
+ puts trace if TRACE_APP
23
+ end
data/lib/rcli.rb ADDED
@@ -0,0 +1,65 @@
1
+ ### Core Libraries
2
+ require 'rubygems'
3
+ require 'text'
4
+ require 'YAML'
5
+ require 'pp'
6
+ require 'pathname'
7
+ require 'highline/import'
8
+
9
+ ### Globals
10
+ $verbose = false # set to true by command line
11
+ DS = File::SEPARATOR # / on unix, \ on windows. DS is a shortcut and faster to type
12
+
13
+
14
+ require 'core/shared/rcli_installation.rb'
15
+
16
+ class Rcli
17
+
18
+ include Rcli::Installation
19
+
20
+ SRC_PATH = File.expand_path('~/lib/ruby/rcli_framework')
21
+
22
+ GEM_ROOT = File.dirname(File.dirname(__FILE__))
23
+ GEM_LIB = GEM_ROOT + DS + 'lib'
24
+ GEM_BIN = GEM_ROOT + DS + 'bin'
25
+ GEM_CONFIG = GEM_ROOT + DS + 'lib' + DS + 'config'
26
+
27
+ RCLI_DOTFOLDER = File.expand_path("~" + DS + '.rcli')
28
+
29
+ if File.exists? (RCLI_DOTFOLDER + DS + 'config.yml')
30
+ RCLI_CONFIG = YAML.load_file(RCLI_DOTFOLDER + DS + 'config.yml')
31
+ else
32
+ RCLI_CONFIG = YAML.load_file(GEM_LIB + DS + 'config' + DS + 'application.yml')
33
+ end
34
+
35
+ @@trace_app = false
36
+ @@script_root = 'uninitialized'
37
+ @@script_config = nil
38
+ @@type = :app
39
+
40
+ def self.script_root ; @@script_root ; end
41
+ def self.script_root=(sr) ;
42
+ @@script_root = sr ;
43
+ if @@type == :app
44
+ @@script_config = YAML.load_file(sr + DS + 'config' + DS + 'application.yml')
45
+ else
46
+ @@script_config = RCLI_CONFIG
47
+ end
48
+ end
49
+ def self.script_config ; @@script_config ; end
50
+ def self.script_config=(sc) ; @@script_config = sc ; end
51
+ def self.trace_app ; @@trace_app ; end
52
+ def self.trace_app=(ta) ; @@trace_app = ta ; end
53
+ def self.type ; @@type ; end
54
+ def self.type=(t) ; @@type = t ; end
55
+
56
+ def self.go ; Commander.new.go ; end
57
+ end
58
+
59
+
60
+ ### Application Libraries
61
+ require 'core/traceable_factory'
62
+ require 'core/actions'
63
+ require 'core/global_functions'
64
+ require 'vendor/trollop'
65
+ require 'core/commander'
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'rcli'
4
+
5
+ #Rcli.trace_app = true # Uncomment if you want to enable tracing.
6
+
7
+ ### LAUNCH RCLIAPPNAME
8
+ Rcli.script_root = Pathname(__FILE__).realpath.parent.to_s
9
+ Commander.new.go
@@ -0,0 +1,12 @@
1
+ class DefaultCommand < Command
2
+
3
+ #description "Your application description (showed in help) goes here"
4
+ #usage "RCLIAPPNAME [-hv]"
5
+
6
+ def main
7
+ # script code goes here:
8
+
9
+ end
10
+
11
+
12
+ end
@@ -0,0 +1,6 @@
1
+ class VersionCommand < Command
2
+
3
+ def main
4
+ puts "RCLIAPPNAME -- version 0.1a"
5
+ end
6
+ end