lightning 0.3.1 → 0.3.2

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.
@@ -0,0 +1,167 @@
1
+ lightning(1) -- Speed for your shell
2
+ ====================================
3
+
4
+ ## SYNOPSIS
5
+
6
+ lightning [-h|--help] [-v|--version] COMMAND [ARGS]
7
+
8
+ ## DESCRIPTION
9
+
10
+ `lightning` is a commandline framework that lets users wrap commands with shell functions that are able to refer (translate) to any filesystem path by its basename. To achieve this, a group of paths to be translated are defined with shell globs. These shell globs, known as a lightning _bolt_, are then applied to commands to produce functions. In addition to translating basenames to full paths, lightning _functions_ can autocomplete these basenames, resolve conflicts if they have the same name, leave any non-basename arguments untouched, and autocomplete directories above and below a basename.
11
+
12
+ To make bolts shareable between users and functions easier to create, `lightning` has _generators_. A _generator_ generates filesystem-specific globs for a bolt. `lightning` comes with some default generators. Users can make their own generators with generator plugins placed under ~/.lightning/generators/.
13
+
14
+ ## COMMANDS
15
+
16
+ `lightning` comes with the following commands, some which have subcommands. Commands and subcommands can be abbreviated i.e. 'function create grep ruby' -> 'f c grep ruby'. Users can define their own commands by placing command plugins under ~/.lightning/commands/.
17
+
18
+ * `bolt`:
19
+ Commands for managing bolts. Defaults to listing them.
20
+ * `complete`:
21
+ Prints a function's completions based on the last argument.
22
+
23
+ * `function`:
24
+ Commands for managing functions. Defaults to listing them.
25
+ * `generator`:
26
+ Lists available generators.
27
+ * `install`:
28
+ Builds shell functions and installs them into FILE to be sourced by shell.
29
+ * `shell_command`:
30
+ Commands for managing shell commands. Defaults to listing them.
31
+ * `translate`:
32
+ Translates each argument and prints it on a separate line.
33
+
34
+ ## CREATE FUNCTIONS
35
+
36
+ There are two nonexclusive ways of creating functions. The first involves combining bolts with individual shell commands. Here are the steps involved:
37
+
38
+ * Create a bolt with shell globs. This step can be skipped if a bolt has a generator with the same name.
39
+ # Globs are quoted to prevent filename expansion.
40
+ $ lightning bolt create code '~/code/fork/\*' '~/code/gems/\*'
41
+ Created bolt 'code'
42
+
43
+ * Create function(s) for that bolt by applying to shell commands.
44
+ $ lightning function create cd code
45
+ Created function 'cd-code'
46
+ $ lightning function create grep code
47
+ Created function 'grep-code'
48
+ * Generate and load functions into shell
49
+ $ lightning-reload
50
+ Created ~/.lightning/function.sh
51
+ Loaded ~/.lightning/function.sh
52
+
53
+ The second, more brute-force way of creating functions is to make global functions. Global functions are made from combining each global bolt with each global shell command. For example, 4 global bolts combined with 7 global commands will make 28 global functions.
54
+
55
+ # First make bolts global since bolts aren't global by default
56
+ $ lg bolt global on python clojure ruby
57
+ Global on for bolts python, clojure, ruby
58
+
59
+ # Then add the global commands
60
+ $ lg shell_command create vim
61
+ Created shell command 'vim'
62
+ $ lg shell_command create grep
63
+ Created shell command 'grep'
64
+ $ lightning-reload
65
+
66
+ # Verify global functions
67
+ $ lightning function list
68
+ grep-clojure
69
+ grep-python
70
+ grep-ruby
71
+ vim-clojure
72
+ vim-python
73
+ vim-ruby
74
+
75
+ ## LIGHTNINGRC
76
+
77
+ `lightning`'s configuration is stored in ~/.lightningrc as YAML. Since it's human readable it's easy to modify. However, `lightning` depends on this file to function and will fail if the file has a syntax error. Modifying this file is only recommended if you need to modify existing functions, bolts or global commands in a way that the lightning commands can't. To read up on the config file format see _http://tagaholic.me/lightning/doc/Lightning/Config.html_.
78
+
79
+ ## INSTALLATION
80
+
81
+ Install with either rip or rubygems:
82
+ $ rip install git://github.com/cldwalker/lightning.git
83
+ # OR
84
+ $ sudo gem install yard # to install documentation correctly
85
+ $ sudo gem install lightning
86
+
87
+ If you've installed with rubygems and the command `time lightning` takes longer than 0.05 seconds, I *strongly recommend* installing with rip, http://hellorip.com. Your startup time directly effects your autocompletion speed with lightning.
88
+
89
+ Once lightning is installed, we need to do a one-time setup:
90
+
91
+ # To see available install options
92
+ $ lightning install -h
93
+
94
+ # Installs lightning's core files
95
+ $ lightning install && source ~/.lightning/functions.sh
96
+ Created ~/.lightning_yml
97
+ Created ~/.lightning/functions.sh
98
+
99
+ # To have lightning's functionality loaded when your shell starts up
100
+ echo source ~/.lightning/functions.sh >> ~/.bashrc
101
+ # or for zsh
102
+ echo source ~/.lightning/functions.sh >> ~/.zshrc
103
+
104
+ ## EXAMPLES
105
+
106
+ Get help on any command:
107
+
108
+ $ lightning function -h
109
+ $ lightning bolt -h
110
+
111
+ List functions:
112
+
113
+ # All functions
114
+ $ lightning function list
115
+ # All functions from ruby bolt
116
+ $ lightning function list --bolt=ruby
117
+ # All functions from global command echo
118
+ $ lightning function list --command=echo
119
+
120
+ Regenerate functions and source them into the shell:
121
+
122
+ # Call every time for changes to bolts and functions to take effect
123
+ $ lightning-reload
124
+
125
+ Manage global shell commands:
126
+
127
+ $ lightning shell_command list
128
+ $ lightning shell_command create cd
129
+ $ lightning shell_command delete cd
130
+
131
+ Manage/edit bolts:
132
+
133
+ $ lightning bolt list
134
+ $ lightning bolt delete ruby
135
+ $ lightning bolt alias ruby r
136
+ $ lightning bolt global off ruby gem local_ruby
137
+
138
+ Generate a bolt using a generator:
139
+
140
+ # Generates ruby bolt with ruby generator
141
+ $ lightning bolt generate ruby
142
+ # Generates ruby19 bolt with ruby generator
143
+ $ lightning bolt generate ruby19 ruby
144
+ # Test what ruby bolt generates
145
+ $ lightning bolt generate ruby --test
146
+
147
+ Test what a function will execute:
148
+
149
+ # Normal execution
150
+ $ cp-gem -r rubygems-update-1.3.6 .
151
+ # Prints cp-gem's translated arguments, one per line
152
+ $ lightning translate cp-gem -r rubygems-update-1.3.6 .
153
+ -r
154
+ /Library/Ruby/Gems/1.8/gems/rubygems-update-1.3.6
155
+ .
156
+
157
+ ## BUGS
158
+
159
+ Please report bugs at _http://github.com/cldwalker/lightning/issues_.
160
+
161
+ ## COPYRIGHT
162
+
163
+ `lightning` is Copyright (C) 2010 Gabriel Horner
164
+
165
+ ## SEE ALSO
166
+
167
+ <http://tagaholic.me/lightning>, <http://tagaholic.me/lightning/doc/>, <http://github.com/cldwalker/lightning>
@@ -0,0 +1,119 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ context "bolt command" do
4
+ def bolt(*args)
5
+ run_command :bolt, args
6
+ end
7
+
8
+ def command_wont_find(bolt)
9
+ mock(Commands).puts "Can't find bolt '#{bolt}'"
10
+ end
11
+
12
+ def create_bolt(bolt='abcd')
13
+ config.bolts[bolt] = Lightning::Config.bolt(['/a/b/c/d'])
14
+ end
15
+
16
+ test 'list lists bolts' do
17
+ mock(Commands).puts config.bolts.keys.sort
18
+ bolt 'list'
19
+ end
20
+
21
+ test 'list lists bolts and aliases with --alias' do
22
+ mock(Commands).print_sorted_hash({"app"=>nil, "wild_dir"=>"w"})
23
+ bolt 'list', '--alias'
24
+ end
25
+
26
+ test 'alias aliases a bolt' do
27
+ create_bolt
28
+ mock(Commands).save_and_say /Aliased.*'abcd'.*'ab'/
29
+ bolt 'alias', 'abcd', 'ab'
30
+ config.bolts['abcd']['alias'].should == 'ab'
31
+ end
32
+
33
+ test "alias prints error for nonexistent bolt" do
34
+ command_wont_find 'zzz'
35
+ bolt 'alias', 'zzz', 'z'
36
+ end
37
+
38
+ test "create creates a bolt" do
39
+ mock(Commands).save_and_say /Created.*'blah'/
40
+ paths = '/some/path', '/some/path2'
41
+ bolt 'create', 'blah', *paths
42
+ config.bolts['blah'] = Lightning::Config.bolt(paths)
43
+ end
44
+
45
+ test 'delete deletes a bolt' do
46
+ mock(Commands).save_and_say /Deleted.*'blah'/
47
+ bolt 'delete', 'blah'
48
+ config.bolts['blah'].should.be.nil
49
+ end
50
+
51
+ test 'delete prints error for nonexistent bolt' do
52
+ command_wont_find 'zzz'
53
+ bolt 'delete', 'zzz'
54
+ end
55
+
56
+ test "generate generates bolt" do
57
+ mock(Generator).run('ruby19', :once=>'ruby', :test=>nil)
58
+ bolt 'generate', 'ruby19', 'ruby'
59
+ end
60
+
61
+ test "generate test generates bolt with --test" do
62
+ mock(Generator).run('ruby19', :once=>'ruby', :test=>true)
63
+ bolt 'generate', 'ruby19', 'ruby', '--test'
64
+ end
65
+
66
+ test 'show shows bolt' do
67
+ create_bolt
68
+ mock(Commands).puts(/globs:.*c\/d/m)
69
+ bolt 'show', 'abcd'
70
+ end
71
+
72
+ test 'show shows bolt given alias' do
73
+ create_bolt
74
+ config.bolts['abcd']['alias'] = 'ab'
75
+ mock(Commands).puts(/globs:.*c\/d.*alias: ab/m)
76
+ bolt 'show', 'ab'
77
+ end
78
+
79
+ test 'show prints error for nonexistent bolt' do
80
+ command_wont_find 'zzz'
81
+ bolt 'show', 'zzz'
82
+ end
83
+
84
+ test 'global prints error if first argument invalid' do
85
+ mock(Commands).puts(/First argument must be/)
86
+ bolt 'global', 'zero', 'ok'
87
+ end
88
+
89
+ context 'global' do
90
+ before_all {create_bolt('foo'); create_bolt('bar') }
91
+
92
+ test 'sets bolts on' do
93
+ mock(Commands).save_and_say /Global on.* foo, bar/
94
+ bolt 'global', 'on', 'foo', 'bar'
95
+ config.bolts['foo']['global'].should == true
96
+ config.bolts['bar']['global'].should == true
97
+ end
98
+
99
+ test 'on prints error for nonexistent bolt' do
100
+ command_wont_find 'far'
101
+ mock(Commands).save_and_say /Global on.* foo/
102
+ bolt 'global', 'on', 'foo', 'far'
103
+ end
104
+
105
+ test 'sets bolts off' do
106
+ mock(Commands).save_and_say /Global off.* foo, bar/
107
+ bolt 'global', 'off', 'foo', 'bar'
108
+ config.bolts['foo']['global'].should == nil
109
+ config.bolts['bar']['global'].should == nil
110
+ end
111
+
112
+ test 'off prints error for nonexistent bolt' do
113
+ command_wont_find 'far'
114
+ mock(Commands).save_and_say /Global off.* foo/
115
+ bolt 'global', 'off', 'foo', 'far'
116
+ end
117
+ after_all { config.bolts.delete('bar'); config.bolts.delete('foo') }
118
+ end
119
+ end
@@ -1,7 +1,14 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  # depends on test/lightning.yml
4
- context "Bolt generates correct command from" do
4
+ context "Bolt generates functions from" do
5
+ test "non-global bolt" do
6
+ config.bolts['wild_dir']['functions'] = ['mv']
7
+ Lightning.functions['mv-w'].is_a?(Function).should == true
8
+ Lightning.functions.delete('mv-w')
9
+ config.bolts['wild_dir'].delete('functions')
10
+ end
11
+
5
12
  assert "shell command" do
6
13
  Lightning.functions['less-app'].is_a?(Function)
7
14
  end
@@ -2,7 +2,7 @@ require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  context "Builder" do
4
4
  def build
5
- Lightning.config.source_file = source_file
5
+ config.source_file = source_file
6
6
  Builder.run
7
7
  end
8
8
 
@@ -11,16 +11,16 @@ context "Builder" do
11
11
  end
12
12
 
13
13
  test "prints error when unable to build" do
14
- Lightning.config[:shell] = 'blah'
14
+ config[:shell] = 'blah'
15
15
  capture_stdout { build }.should =~ /No.*exists.*blah shell/
16
- Lightning.config[:shell] = nil
16
+ config[:shell] = nil
17
17
  end
18
18
 
19
19
  test "with non-default shell builds" do
20
- Lightning.config[:shell] = 'zsh'
20
+ config[:shell] = 'zsh'
21
21
  mock(Builder).zsh_builder(anything) { '' }
22
22
  build
23
- Lightning.config[:shell] = nil
23
+ config[:shell] = nil
24
24
  end
25
25
 
26
26
  test "warns about existing commands being overridden" do
@@ -1,71 +1,43 @@
1
1
  require File.join(File.dirname(__FILE__), 'test_helper')
2
2
 
3
3
  context "Commands:" do
4
- # this test seems to run much longer than expected i.e. 0.02
5
- # rr and raising?
6
4
  test "run_command handles unexpected error" do
7
5
  mock($stderr).puts(/^Error: Unexpected/)
8
6
  mock(Commands).complete(anything) { raise "Unexpected" }
9
7
  run_command :complete
10
8
  end
11
9
 
12
- test "complete defaults to ARGV if no ENV['COMP_LINE']" do
13
- mock(Completion).complete('o-a Col', anything)
14
- capture_stdout { run_command(:complete, ['o-a', 'Col']) }
10
+ test "generic command prints usage with -h" do
11
+ capture_stdout { run_command :install, ['-h'] }.should =~ /^Usage/
15
12
  end
16
13
 
17
- test "complete prints usage for no arguments" do
18
- capture_stdout { run_command(:complete, []) }.should =~ /^Usage/
14
+ test "generic command prints error if invalid subcommand" do
15
+ mock(Commands).puts /Invalid.*'blah'/, anything
16
+ run_command 'function', ['blah']
19
17
  end
20
18
 
21
- test "complete prints error for invalid command" do
22
- capture_stdout { run_command(:complete, ['invalid','invalid']) }.should =~ /^#Error.*Please/m
19
+ test "generic command can take abbreviated subcommand" do
20
+ mock(Commands).list_function(anything)
21
+ run_command 'function', ['l']
23
22
  end
24
23
 
25
- test "translate prints usage for no arguments" do
26
- capture_stdout { run_command(:translate, []) }.should =~ /^Usage/
24
+ def bolt_expects_subcommand_args(bolt, expected)
25
+ Commands.instance_variable_set "@command", bolt
26
+ actual = Commands.send(:subcommand_required_args)
27
+ expected.all? {|k,v| actual[k] == v }.should == true
27
28
  end
28
29
 
29
- test "translate prints error for invalid command" do
30
- capture_stdout { run_command(:translate, %w{invalid blah}) }.should =~ /#Error/
30
+ test "has correct number of subcommands for bolt" do
31
+ bolt_expects_subcommand_args 'function', {"delete"=>1, "create"=>2}
31
32
  end
32
33
 
33
- test "command prints usage with -h" do
34
- capture_stdout { run_command :install, ['-h'] }.should =~ /^Usage/
34
+ test "has correct number of subcommands for shell_command" do
35
+ bolt_expects_subcommand_args 'shell_command', {"delete"=>1, "create"=>1}
35
36
  end
36
37
 
37
- context "first install" do
38
- before_all {
39
- @old_config = Lightning.config
40
- Lightning.config = Lightning::Config.new({})
41
- @old_functions = Lightning.functions
42
- Lightning.functions = nil
43
-
44
- mock(Lightning.config).save.times(2)
45
- mock(Commands).first_install? { true }.times(2)
46
- stub.instance_of(Generator).call_generator { [] }
47
- mock(File).open(anything, 'w')
48
- @stdout = capture_stdout { run_command :install }
49
- }
50
-
51
- assert "generates default bolts" do
52
- Generator::DEFAULT_GENERATORS.all? {|e| Lightning.config[:bolts].key?(e) }
53
- end
54
-
55
- assert "default bolts are global" do
56
- Generator::DEFAULT_GENERATORS.all? {|e| Lightning.config[:bolts][e]['global'] }
57
- end
58
-
59
- test "builds 8 default functions" do
60
- expected = %w{cd-gem cd-local_ruby cd-ruby cd-wild echo-gem echo-local_ruby echo-ruby echo-wild}
61
- Lightning.functions.keys.sort.should == expected
62
- end
63
-
64
- test "prints correct install message" do
65
- @stdout.should =~ /^Created.*lightningrc\nCreated.*functions\.sh for bash/m
66
- end
67
-
68
- after_all { Lightning.config = @old_config; Lightning.functions = @old_functions }
38
+ test "has correct number of subcommands for bolt" do
39
+ bolt_expects_subcommand_args 'bolt', {"alias"=>2, 'create'=>2, 'delete'=>1,
40
+ 'generate'=>1, 'global'=>2, 'show'=>1}
69
41
  end
70
42
 
71
43
  context "run" do
@@ -9,7 +9,7 @@ context "Completion" do
9
9
  }
10
10
 
11
11
  def tab(input, expected, complete_regex=false)
12
- Lightning.config[:complete_regex] = complete_regex
12
+ config[:complete_regex] = complete_regex
13
13
  mock(Commands).puts(expected)
14
14
  run_command :complete, [@command, 'cd-test '+ input]
15
15
  end
@@ -100,6 +100,8 @@ context "Completion" do
100
100
  tab '[]', Completion.error_array('Invalid regular expression.'), true
101
101
  end
102
102
  end
103
+
104
+ after_all { Lightning.functions.delete('blah') }
103
105
  end
104
106
 
105
107
  context "Completion misc" do
@@ -0,0 +1,59 @@
1
+ require File.join(File.dirname(__FILE__), 'test_helper')
2
+
3
+ context "Core commands" do
4
+ test "complete defaults to ARGV if no ENV['COMP_LINE']" do
5
+ mock(Completion).complete('o-a Col', anything)
6
+ capture_stdout { run_command(:complete, ['o-a', 'Col']) }
7
+ end
8
+
9
+ test "complete prints usage for no arguments" do
10
+ capture_stdout { run_command(:complete, []) }.should =~ /^Usage/
11
+ end
12
+
13
+ test "complete prints error for invalid command" do
14
+ capture_stdout { run_command(:complete, ['invalid','invalid']) }.should =~ /^#Error.*Please/m
15
+ end
16
+
17
+ test "translate prints usage for no arguments" do
18
+ capture_stdout { run_command(:translate, [])
19
+ }.should =~ /'lightning translate'.*incorrectly.*Usage:/m
20
+ end
21
+
22
+ test "translate prints error for invalid command" do
23
+ capture_stdout { run_command(:translate, %w{invalid blah}) }.should =~ /#Error/
24
+ end
25
+
26
+ context "first install" do
27
+ before_all {
28
+ @old_config = config
29
+ Lightning.config = Lightning::Config.new({})
30
+ @old_functions = Lightning.functions
31
+ Lightning.functions = nil
32
+
33
+ mock(config).save.times(2)
34
+ mock(Commands).first_install? { true }.times(2)
35
+ stub.instance_of(Generator).call_generator { [] }
36
+ mock(File).open(anything, 'w')
37
+ @stdout = capture_stdout { run_command :install }
38
+ }
39
+
40
+ assert "generates default bolts" do
41
+ Generator::DEFAULT_GENERATORS.all? {|e| config[:bolts].key?(e) }
42
+ end
43
+
44
+ assert "default bolts are global" do
45
+ Generator::DEFAULT_GENERATORS.all? {|e| config[:bolts][e]['global'] }
46
+ end
47
+
48
+ test "builds 8 default functions" do
49
+ expected = %w{cd-gem cd-local_ruby cd-ruby cd-wild echo-gem echo-local_ruby echo-ruby echo-wild}
50
+ Lightning.functions.keys.sort.should == expected
51
+ end
52
+
53
+ test "prints correct install message" do
54
+ @stdout.should =~ /^Created.*lightningrc\nCreated.*functions\.sh for bash/m
55
+ end
56
+
57
+ after_all { Lightning.config = @old_config; Lightning.functions = @old_functions }
58
+ end
59
+ end