huffshell 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+ gemspec
3
+ gem 'rspec'
4
+ gem 'colorize'
data/Gemfile.lock ADDED
@@ -0,0 +1,26 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ huffshell (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ colorize (0.5.8)
10
+ diff-lcs (1.1.3)
11
+ rspec (2.10.0)
12
+ rspec-core (~> 2.10.0)
13
+ rspec-expectations (~> 2.10.0)
14
+ rspec-mocks (~> 2.10.0)
15
+ rspec-core (2.10.1)
16
+ rspec-expectations (2.10.0)
17
+ diff-lcs (~> 1.1.3)
18
+ rspec-mocks (2.10.1)
19
+
20
+ PLATFORMS
21
+ ruby
22
+
23
+ DEPENDENCIES
24
+ colorize
25
+ huffshell!
26
+ rspec
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'rspec/core/rake_task'
2
+
3
+ RSpec::Core::RakeTask.new('spec')
4
+
5
+ # If you want to make this the default task
6
+ task :default => :spec
data/Readme.md ADDED
@@ -0,0 +1,34 @@
1
+ HuffShell
2
+ ====================
3
+
4
+ HuffShell is a gem for optimizing your ZSH aliases, programtically.
5
+
6
+ The gems looks at your history which can be automatically stored and generates aliases based on your usage. Your history is used to determine what you use the most and generate the shortest commands based on usage.
7
+
8
+ For example, you use 'git' 500 times and you use 'ls -l' 100 times. You should add aliases that are 'g' and 'll'. It could save you hundreds of keystokes.
9
+
10
+ In order to do that, huffshell generates stats of your usage and gives them to you, as you might hope.
11
+
12
+ Features
13
+ ---------------------
14
+
15
+ * Alias suggestion based on history.
16
+ * Examines your system for binaries and aliases and avoids reassigning them.
17
+ * Huffman inspired symbol generation.
18
+ * Handy gem packaging.
19
+ * Works out of the box with oh-my-zsh.
20
+
21
+ Installation
22
+ ---------------------
23
+
24
+ ```script
25
+ # install it
26
+ gem install huffman
27
+
28
+ # need to be able to access this from the gem
29
+ alias > ~/.aliases.cache
30
+ huffshell
31
+
32
+ # cleanup
33
+ alias > ~/.aliases.cache
34
+ ```
data/bin/huffshell ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'huffshell'
4
+ require 'pp'
5
+
6
+ cs = CommandSuggestor.new
7
+ history_filename = '~/.zsh_history'
8
+
9
+ OhMyZshReader.new(history_filename).
10
+ shell_commands.
11
+ each{ |l| cs.add(l) }
12
+
13
+ cs.truncate!(30)
14
+ puts cs.to_print
@@ -0,0 +1,42 @@
1
+ require 'colorize'
2
+
3
+ class CommandSuggestion
4
+ attr_accessor :wordlist
5
+
6
+ SHORT_ENOUGH = 3
7
+
8
+ def initialize(wordlist)
9
+ @wordlist = wordlist
10
+ end
11
+
12
+ def to_s
13
+ if exists?
14
+ "'#{command}' => #{abbreviation} taken :("
15
+ else
16
+ "'#{command}' => " + "#{abbreviation}".green
17
+ end
18
+ end
19
+
20
+ def abbreviation
21
+ wordlist.map{|w| CommandWord.suggested_letter(w) }.join.downcase
22
+ end
23
+
24
+ private
25
+
26
+ def command
27
+ wordlist.join(" ")
28
+ end
29
+
30
+ def exists?
31
+ binary_checker.exist? || alias_checker.exist?(abbreviation)
32
+ end
33
+
34
+ def binary_checker
35
+ BinaryChecker.new(abbreviation)
36
+ end
37
+
38
+ def alias_checker
39
+ AliasChecker.new("~/.aliases.cache")
40
+ end
41
+
42
+ end
@@ -0,0 +1,24 @@
1
+ class CommandSuggestor
2
+ attr_accessor :wordtree
3
+
4
+ def initialize()
5
+ @wordtree = WordTree.new
6
+ end
7
+
8
+ def add(line)
9
+ sl = ScriptLine.new(line)
10
+ return unless sl.valid?
11
+ wordtree.add(sl)
12
+ end
13
+
14
+ def truncate!(minimum)
15
+ wordtree.root.truncate!(minimum)
16
+ end
17
+
18
+ def to_print
19
+ wordtree.root.map do |n|
20
+ cs = CommandSuggestion.new(n.word_list)
21
+ "#{n.to_print.chomp} #{cs.to_s}"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ class CommandWord
2
+ def self.clean(word)
3
+ word.gsub(/(\-)+/, '') #.downcase
4
+ end
5
+
6
+ def self.suggested_letter(word)
7
+ word.gsub(/(^\W)+/,"")[0].downcase
8
+ rescue
9
+ nil
10
+ end
11
+ end
data/lib/huffshell.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'readers/oh_my_zsh_reader'
2
+
3
+ require 'command/command_word'
4
+ require 'command/command_suggestor'
5
+ require 'command/command_suggestion'
6
+
7
+ require 'shell/alias_line'
8
+ require 'shell/script_line'
9
+ require 'shell/alias_checker'
10
+ require 'shell/binary_checker'
11
+
12
+ require 'tree/word_tree'
13
+ require 'tree/word_tree_node'
@@ -0,0 +1,35 @@
1
+ require 'iconv' unless String.method_defined?(:encode)
2
+
3
+ class OhMyZshReader
4
+ attr_accessor :file_name, :file_contents
5
+
6
+ def initialize(file_name)
7
+ @file_name = file_name
8
+ @file_contents = File.open(File.expand_path(file_name), 'r').read
9
+
10
+ if String.method_defined?(:encode)
11
+ @file_contents.encode!('UTF-8', 'UTF-8', :invalid => :replace)
12
+ else
13
+ ic = Iconv.new('UTF-8', 'UTF-8//IGNORE')
14
+ @file_contents = ic.iconv(@file_contents)
15
+ end
16
+ end
17
+
18
+ def shell_commands
19
+ filtered_lines.map {|l| l.split(";").last.strip }
20
+ end
21
+
22
+ private
23
+
24
+ def filtered_lines
25
+ raw_lines(file_contents).select{|l| valid_line?(l) }
26
+ end
27
+
28
+ def valid_line?(line)
29
+ line[0] == ":"
30
+ end
31
+
32
+ def raw_lines(file_contents)
33
+ file_contents.split("\n")
34
+ end
35
+ end
@@ -0,0 +1,18 @@
1
+ class AliasChecker
2
+ attr_accessor :filename, :aliases
3
+
4
+ def initialize(filename)
5
+ @filename = filename
6
+ file_contents = File.open(File.expand_path(filename), 'r').read
7
+ lines = file_contents.split("\n")
8
+ @aliases = {}
9
+ lines.each do |l|
10
+ al = AliasLine.new(l)
11
+ @aliases[al.alias_name] = al.command
12
+ end
13
+ end
14
+
15
+ def exist?(alias_name)
16
+ !!@aliases[alias_name]
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ class AliasLine
2
+ attr_accessor :line
3
+
4
+ def initialize(line)
5
+ @line = line
6
+ end
7
+
8
+ def alias_name
9
+ @line.split("=").first
10
+ end
11
+
12
+ def command
13
+ c = @line.split("=")[1]
14
+ c[1..(c.size-2)]
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ class BinaryChecker
2
+ def initialize(command)
3
+ @command = command
4
+ end
5
+
6
+ def exist?
7
+ # would love something better
8
+ out = `command -v #{@command} >/dev/null 2>&1`
9
+ $?.to_s.scan("exit 0") != []
10
+ end
11
+ end
@@ -0,0 +1,27 @@
1
+ class ScriptLine
2
+ attr_accessor :line, :words, :clean_words
3
+
4
+ def initialize(l)
5
+ @line = l.strip
6
+ @words = l.split(/[ \t]+/)
7
+ @clean_words = @words.map{|w| CommandWord.clean(w) }
8
+ end
9
+
10
+ def command
11
+ clean_words.first
12
+ end
13
+
14
+ def valid?
15
+ !(comment? || empty?)
16
+ end
17
+
18
+ private
19
+
20
+ def comment?
21
+ @line[0] == "#"
22
+ end
23
+
24
+ def empty?
25
+ @line.size == 0
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ class WordTree
2
+ attr_accessor :root, :line_count
3
+
4
+ def initialize
5
+ @root = WordTreeNode.new
6
+ @line_count = 0
7
+ end
8
+
9
+ def add(line)
10
+ @line_count += 1
11
+ root.add(line, 0)
12
+ end
13
+
14
+ def truncate!(minimum)
15
+ root.truncate!(minimum)
16
+ end
17
+
18
+ def to_print
19
+ root.to_print
20
+ end
21
+ end
@@ -0,0 +1,68 @@
1
+ require 'colorize'
2
+
3
+ class WordTreeNode
4
+ include Enumerable
5
+
6
+ attr_accessor :word, :cleanword, :children, :line_count, :level, :parent
7
+
8
+ def initialize(word = nil, level = 0, parent = nil)
9
+ @word = word
10
+ @cleanword = CommandWord.clean(word) if word
11
+ @children = {}
12
+ @line_count = 0
13
+ @level = level
14
+ @parent = parent
15
+ end
16
+
17
+ def add(line, level = 0)
18
+ word = line.words[level]
19
+ clean_word = line.clean_words[level]
20
+ @line_count += 1
21
+ return unless word
22
+
23
+ @children[word] ||= WordTreeNode.new(word, level + 1, self)
24
+ @children[word].add(line, level + 1)
25
+ end
26
+
27
+ def each &block
28
+ children.values.sort.each do |v|
29
+ block.call(v)
30
+ v.each do |q|
31
+ block.call(q)
32
+ end
33
+ end
34
+ end
35
+
36
+ def <=> b
37
+ b.line_count <=> line_count
38
+ end
39
+
40
+ def words
41
+ children.keys.uniq
42
+ end
43
+
44
+ def root?
45
+ word.nil?
46
+ end
47
+
48
+ def truncate!(minimum)
49
+ children.select!{|k, v| v.line_count >= minimum }
50
+ children.each{|k, v| v.truncate!(minimum) }
51
+ end
52
+
53
+ def word_list
54
+ list = [self.word]
55
+ node = self
56
+ while node = node.parent
57
+ next if node.word.nil?
58
+ list << node.word
59
+ end
60
+ list.reverse
61
+ end
62
+
63
+ def to_print
64
+ return "" if root?
65
+ "#{("\t" * (level - 1))}" + "#{word}".green + " #{line_count}:\n"
66
+ end
67
+
68
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: huffshell
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Paul McKellar
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-18 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: A parser and recommendation system for your shell aliases based on your
15
+ shell history
16
+ email: paul.mckellar@gmail.com
17
+ executables:
18
+ - huffshell
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - lib/command/command_suggestion.rb
23
+ - lib/command/command_suggestor.rb
24
+ - lib/command/command_word.rb
25
+ - lib/huffshell.rb
26
+ - lib/readers/oh_my_zsh_reader.rb
27
+ - lib/shell/alias_checker.rb
28
+ - lib/shell/alias_line.rb
29
+ - lib/shell/binary_checker.rb
30
+ - lib/shell/script_line.rb
31
+ - lib/tree/word_tree.rb
32
+ - lib/tree/word_tree_node.rb
33
+ - bin/huffshell
34
+ - Gemfile
35
+ - Gemfile.lock
36
+ - Rakefile
37
+ - Readme.md
38
+ homepage: http://rubygems.org/gems/huffshell
39
+ licenses: []
40
+ post_install_message:
41
+ rdoc_options: []
42
+ require_paths:
43
+ - lib
44
+ required_ruby_version: !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ required_rubygems_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 1.8.10
59
+ signing_key:
60
+ specification_version: 3
61
+ summary: Automatic shell alias recommondations based on usage!
62
+ test_files: []