yap-shell 0.6.0 → 0.7.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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.travis.lock +104 -0
  3. data/bin/yap +6 -0
  4. data/bin/yap-dev +37 -0
  5. data/lib/yap.rb +29 -39
  6. data/lib/yap/addon.rb +24 -0
  7. data/lib/yap/addon/base.rb +52 -0
  8. data/lib/yap/addon/export_as.rb +12 -0
  9. data/lib/yap/addon/loader.rb +84 -0
  10. data/lib/yap/addon/path.rb +56 -0
  11. data/lib/yap/addon/rc_file.rb +21 -0
  12. data/lib/yap/addon/reference.rb +22 -0
  13. data/lib/yap/cli.rb +4 -0
  14. data/lib/yap/cli/commands.rb +6 -0
  15. data/lib/yap/cli/commands/addon.rb +14 -0
  16. data/lib/yap/cli/commands/addon/disable.rb +35 -0
  17. data/lib/yap/cli/commands/addon/enable.rb +35 -0
  18. data/lib/yap/cli/commands/addon/list.rb +37 -0
  19. data/lib/yap/cli/commands/addon/search.rb +99 -0
  20. data/lib/yap/cli/commands/generate.rb +13 -0
  21. data/lib/yap/cli/commands/generate/addon.rb +258 -0
  22. data/lib/yap/cli/commands/generate/addonrb.template +22 -0
  23. data/lib/yap/cli/commands/generate/gemspec.template +25 -0
  24. data/lib/yap/cli/commands/generate/license.template +21 -0
  25. data/lib/yap/cli/commands/generate/rakefile.template +6 -0
  26. data/lib/yap/cli/commands/generate/readme.template +40 -0
  27. data/lib/yap/cli/options.rb +162 -0
  28. data/lib/yap/cli/options/addon.rb +64 -0
  29. data/lib/yap/cli/options/addon/disable.rb +62 -0
  30. data/lib/yap/cli/options/addon/enable.rb +63 -0
  31. data/lib/yap/cli/options/addon/list.rb +65 -0
  32. data/lib/yap/cli/options/addon/search.rb +76 -0
  33. data/lib/yap/cli/options/generate.rb +59 -0
  34. data/lib/yap/cli/options/generate/addon.rb +63 -0
  35. data/lib/yap/configuration.rb +10 -3
  36. data/lib/yap/gem_helper.rb +195 -0
  37. data/lib/yap/gem_tasks.rb +6 -0
  38. data/lib/yap/shell.rb +1 -1
  39. data/lib/yap/shell/repl.rb +1 -1
  40. data/lib/yap/shell/version.rb +1 -1
  41. data/lib/yap/world.rb +45 -7
  42. data/rcfiles/yaprc +90 -10
  43. data/spec/features/addons/generating_an_addon_spec.rb +55 -0
  44. data/spec/features/addons/using_an_addon_spec.rb +182 -0
  45. data/spec/features/aliases_spec.rb +6 -6
  46. data/spec/features/grouping_spec.rb +18 -18
  47. data/spec/features/line_editing_spec.rb +9 -1
  48. data/spec/features/redirection_spec.rb +12 -3
  49. data/spec/spec_helper.rb +21 -11
  50. data/spec/support/matchers/have_printed.rb +38 -0
  51. data/spec/support/yap_spec_dsl.rb +24 -6
  52. data/yap-shell.gemspec +6 -11
  53. metadata +51 -45
  54. data/addons/history/README.md +0 -16
  55. data/addons/history/history.rb +0 -58
  56. data/addons/history_search/history_search.rb +0 -197
  57. data/addons/keyboard_macros/keyboard_macros.rb +0 -425
  58. data/addons/keyboard_macros/lib/keyboard_macros/cycle.rb +0 -38
  59. data/addons/prompt/Gemfile +0 -1
  60. data/addons/prompt/right_prompt.rb +0 -17
  61. data/addons/prompt_updates/prompt_updates.rb +0 -28
  62. data/addons/tab_completion/Gemfile +0 -0
  63. data/addons/tab_completion/lib/tab_completion/basic_completion.rb +0 -151
  64. data/addons/tab_completion/lib/tab_completion/completer.rb +0 -62
  65. data/addons/tab_completion/lib/tab_completion/custom_completion.rb +0 -33
  66. data/addons/tab_completion/lib/tab_completion/dsl_methods.rb +0 -7
  67. data/addons/tab_completion/tab_completion.rb +0 -174
  68. data/lib/tasks/addons.rake +0 -97
  69. data/lib/yap/world/addons.rb +0 -181
@@ -1,97 +0,0 @@
1
- namespace :addons do
2
- task :new do
3
- require 'highline'
4
- require 'term/ansicolor'
5
- require 'pathname'
6
-
7
- extend Term::ANSIColor
8
-
9
- yap_path = Pathname.new(File.dirname(__FILE__)).join('../..')
10
- yap_lib_path = yap_path.join('lib')
11
- yap_addons_path = yap_path.join('addons')
12
-
13
- $LOAD_PATH.unshift yap_lib_path
14
- require 'yap'
15
-
16
- cli = HighLine.new
17
- answer = cli.ask("Name for the addon? ")
18
-
19
- addon_name = answer.downcase.gsub(/\W+/, '_')
20
- addon_class_name = addon_name.split('_').map(&:capitalize).join
21
- addon_path = yap_addons_path.join(addon_name)
22
-
23
- loop do
24
- answer = cli.ask("Create #{addon_class_name} addon in #{addon_path}? [Yn] ")
25
- break if answer =~ /y/i
26
- exit 1 if answer =~ /n/i
27
- end
28
- puts "Generating #{addon_class_name}"
29
- puts
30
-
31
- print " Creating #{addon_path} "
32
- FileUtils.mkdir_p addon_path
33
- puts green('done')
34
-
35
- addon_file = addon_path.join("#{addon_name}.rb")
36
- print " Creating #{addon_file} "
37
- File.write addon_file, <<-FILE.gsub(/^\s*\|/, '')
38
- |class #{addon_class_name} < Addon
39
- | def initialize_world(world)
40
- | # initialization code here
41
- | end
42
- |end
43
- FILE
44
- puts green('done')
45
- puts
46
- end
47
-
48
- namespace :update do
49
- desc "Update the gemspec based on add-on specific dependnecies"
50
- task :gemspec do
51
- require 'bundler'
52
- runtime_deps = []
53
- development_deps = []
54
- root_dir = File.dirname(__FILE__) + "/../.."
55
- gemfiles = Dir[root_dir + "/addons/**/**/Gemfile"]
56
- gemfiles.each do |gemfile|
57
- bd = Bundler::Definition.build(gemfile, nil, nil)
58
- runtime_deps.push *bd.dependencies.select{ |dep| dep.type == :runtime }
59
- development_deps.push *bd.dependencies.select{ |dep| dep.type == :development }
60
- end
61
-
62
- runtime_h = Hash.new{ |h,name| h[name] = Gem::Dependency.new(name) }
63
- runtime_deps.each { |dep| runtime_h[dep.name] = runtime_h[dep.name].merge(dep) }
64
-
65
- dev_h = Hash.new{ |h,name| h[name] = Gem::Dependency.new(name) }
66
- development_deps.each { |dep| dev_h[dep.name] = dev_h[dep.name].merge(dep) }
67
-
68
- deps_str = ""
69
- deps_str << runtime_h.map do |name, dep|
70
- if dep.requirement.none?
71
- %| spec.add_dependency "#{dep.name}"|
72
- else
73
- %| spec.add_dependency "#{dep.name}", "#{dep.requirement.as_list.first}"|
74
- end
75
- end.join("\n")
76
-
77
- deps_str << dev_h.map do |name, dep|
78
- if dep.requirement.none?
79
- %| spec.add_development_dependency "#{dep.name}"|
80
- else
81
- %| spec.add_development_dependency "#{dep.name}", "#{dep.requirement.as_list.first}"|
82
- end
83
- end.join("\n")
84
-
85
- gemspec = Dir[root_dir + "/*.gemspec"].first || raise("No gemspec found in directory: #{root_dir}")
86
- gemspec = File.expand_path(gemspec)
87
- contents = File.read(gemspec)
88
- new_contents = contents.sub(/(\#--BEGIN_ADDON_GEM_DEPENDENCIES--\#)\s*.*(^.*\#--END_ADDON_GEM_DEPENDENCIES--\#)/mx) do
89
- "#{$1}\n#{deps_str}\n#{$2}"
90
- end
91
-
92
- File.write(gemspec, new_contents)
93
- puts "Updated #{gemspec}"
94
- puts new_contents
95
- end
96
- end
97
- end
@@ -1,181 +0,0 @@
1
- require 'pathname'
2
-
3
- module Yap
4
- class World
5
- module UserAddons
6
- end
7
-
8
- module AddonMethods
9
- module ClassMethods
10
- def load_addon
11
- # no-op, override in subclass if you need to do anything special
12
- # when your addon is first loaded when the shell starts
13
- end
14
-
15
- def addon_name
16
- @addon_name ||= self.name.split(/::/).last.scan(/[A-Z][^A-Z]+/).map(&:downcase).reject{ |f| f == "addon" }.join("_").to_sym
17
- end
18
-
19
- def debug_log(msg)
20
- Treefell['addons'].puts "addon=#{addon_name} #{msg}"
21
- end
22
-
23
- def require(name)
24
- Treefell['shell'].puts "addon is requiring: #{name}"
25
- directory = File.dirname caller[0].split(':').first
26
- lib_path = File.join directory, "lib"
27
- support_file = File.join lib_path, "#{name}.rb"
28
- namespace = self.name.split('::').reduce(Object) do |context,n|
29
- o = context.const_get(n)
30
- break o if o.is_a?(Namespace)
31
- o
32
- end
33
- if File.exists?(support_file) && namespace
34
- Treefell['shell'].puts "#{name} is found in addon, loading #{support_file} in context of #{namespace}"
35
- namespace.module_eval IO.read(support_file), support_file, lineno=1
36
- else
37
- Treefell['shell'].puts "#{name} not found in addon, falling back to super"
38
- super(name)
39
- end
40
- end
41
- end
42
-
43
- module InstanceMethods
44
- def addon_name
45
- @addon_name ||= self.class.addon_name
46
- end
47
-
48
- def debug_log(msg)
49
- self.class.debug_log(msg)
50
- end
51
- end
52
- end
53
-
54
- module Namespace
55
- end
56
-
57
- class Addon
58
- extend AddonMethods::ClassMethods
59
- include AddonMethods::InstanceMethods
60
- end
61
-
62
- module Addons
63
- def self.syntax_ok?(file)
64
- `ruby -c #{file}`
65
- ($?.exitstatus == 0).tap do |result|
66
- Treefell['shell'].puts "is syntax ok?(#{file.inspect}) #{result}"
67
- end
68
- end
69
-
70
- def self.load_rcfiles(files)
71
- Treefell['shell'].puts %|searching for rcfiles:\n * #{files.join("\n * ")}|
72
- files.map do |file|
73
- if File.exists?(file)
74
- Treefell['shell'].puts "rcfile #{file} found, loading."
75
- RcFile.new file
76
- else
77
- Treefell['shell'].puts "rcfile #{file} not found, skipping."
78
- end
79
- end.flatten.compact
80
- end
81
-
82
- def self.load_directories(search_paths)
83
- Treefell['shell'].puts %|searching for addons in:\n * #{search_paths.join("\n * ")}|
84
- search_paths.map do |directory|
85
- Dir["#{directory}/*"].map do |d|
86
- if File.directory?(d)
87
- Treefell['shell'].puts %|addon found: #{d}|
88
- load_directory(d).map(&:new)
89
- else
90
- Treefell['shell'].puts %|file found in add-on search path, skipping.|
91
- nil
92
- end
93
- end
94
- end.flatten.compact
95
- end
96
-
97
- class RcFile < Addon
98
- attr_reader :file
99
-
100
- def initialize(file)
101
- @file = File.expand_path(file)
102
- end
103
-
104
- def initialize_world(world)
105
- Treefell['shell'].puts "initializing rcfile: #{file}"
106
- world.instance_eval File.read(@file), @file
107
- end
108
- end
109
-
110
- def self.load_directory(directory)
111
- directory = File.expand_path(directory)
112
- Treefell['shell'].puts "loading addon from directory: #{directory}"
113
- namespace = File.basename(directory).
114
- split(/[_-]/).
115
- map(&:capitalize).join
116
- namespace = "#{namespace}Addon"
117
-
118
- if Yap::World::UserAddons.const_defined?(namespace)
119
- raise LoadError, "#{namespace} is already defined! Failed loading #{file}"
120
- end
121
-
122
- # Create a wrapper module for every add-on. This is to eliminate
123
- # namespace collision.
124
- addon_module = Module.new do
125
- extend Namespace
126
- extend AddonMethods::ClassMethods
127
- const_set :Addon, Addon
128
- end
129
-
130
- Yap::World::UserAddons.const_set namespace, addon_module
131
- Treefell['shell'].puts "creating addon namespace: Yap::World::UserAddons::#{namespace}"
132
-
133
- lib_path = File.join directory, "lib"
134
- Treefell['shell'].puts "prepending addon path to $LOAD_PATH: #{lib_path}"
135
- $LOAD_PATH.unshift lib_path
136
-
137
- gemfiles = Dir["#{directory}/Gemfile"]
138
- Treefell['shell'].puts "looking for Gemfile in #{namespace} addon directory: #{directory}"
139
- if gemfiles.any?
140
- gemfiles.each do |gemfile|
141
- Treefell['shell'].puts "loading #{gemfile} for addon"
142
- eval File.read(gemfile)
143
- end
144
- else
145
- Treefell['shell'].puts "No Gemfile found for #{namespace} addon"
146
- end
147
-
148
- Dir["#{directory}/*.rb"].map do |addon_file|
149
- load_file(addon_file, namespace:namespace, dir:directory, addon_module:addon_module)
150
- end
151
- ensure
152
- if lib_path
153
- Treefell['shell'].puts "Removing addon #{lib_path} path from $LOAD_PATH"
154
- $LOAD_PATH.delete(lib_path)
155
- end
156
- end
157
-
158
- def self.load_file(file, dir:, namespace:, addon_module:)
159
- Treefell['shell'].puts "loading #{namespace} addon file: #{file}"
160
- klass_name = file.sub(dir, "").
161
- sub(/^#{Regexp.escape(File::Separator)}/, "").
162
- sub(File.extname(file.to_s), "").
163
- split(File::Separator).
164
- map{ |m| m.split(/[_-]/).map(&:capitalize).join }.
165
- join("::")
166
-
167
- addon_module.module_eval IO.read(file), file, lineno=1
168
-
169
- klass_name.split("::").reduce(addon_module) do |ns,name|
170
- if ns.const_defined?(name)
171
- ns.const_get(name)
172
- else
173
- raise("Did not find #{klass_name} in #{file}")
174
- end
175
- end.tap do |loaded_addon|
176
- Treefell['shell'].puts "loaded #{File.dirname(file)} as #{loaded_addon.inspect}"
177
- end
178
- end
179
- end
180
- end
181
- end