alias_metrics 0.1

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.
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ tmp
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format Fuubar
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'http://rubygems.org'
2
+
3
+ group :development do
4
+ gem 'rspec', '~> 2.0'
5
+ gem 'fuubar', "~> 1.0.0"
6
+ gem "rake", "~> 0.9.2.2"
7
+ end
8
+
data/Gemfile.lock ADDED
@@ -0,0 +1,27 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ fuubar (1.0.0)
6
+ rspec (~> 2.0)
7
+ rspec-instafail (~> 0.2.0)
8
+ ruby-progressbar (~> 0.0.10)
9
+ rake (0.9.2.2)
10
+ rspec (2.8.0)
11
+ rspec-core (~> 2.8.0)
12
+ rspec-expectations (~> 2.8.0)
13
+ rspec-mocks (~> 2.8.0)
14
+ rspec-core (2.8.0)
15
+ rspec-expectations (2.8.0)
16
+ diff-lcs (~> 1.1.2)
17
+ rspec-instafail (0.2.2)
18
+ rspec-mocks (2.8.0)
19
+ ruby-progressbar (0.0.10)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ fuubar (~> 1.0.0)
26
+ rake (~> 0.9.2.2)
27
+ rspec (~> 2.0)
data/README ADDED
@@ -0,0 +1,49 @@
1
+ This tool is to visualize alias usage to parse command history. You can evaluate whether you use alias efficiently or not.
2
+ * It can show reduced types and more redusable types
3
+ * It can show how degree you use each alias
4
+
5
+ The visabliable shell scripts is the followings:
6
+ * zsh (${HOME}/.zsh-history)
7
+
8
+
9
+ How to use:
10
+
11
+ $ alias | alias_metrics
12
+
13
+
14
+ Case Study:
15
+
16
+ $ alias | alias_metrics
17
+ >>
18
+
19
+ You reduce 10.25% types (29814 / 290970)
20
+
21
+ If you use alias all, you can reduce more 3.98% types (11575 / 290970)
22
+
23
+
24
+
25
+ You often forget the following alias
26
+
27
+ alias #used #forgot forgot rate(%) command
28
+
29
+ g 9 1530 99.42 git
30
+
31
+ _ 0 210 100.00 sudo
32
+
33
+ gco 24 197 89.14 git checkout
34
+
35
+ ga 516 190 26.91 git add
36
+
37
+ ...
38
+ <<
39
+ I regist alias g=`git`, but I often forgot to use this alias. This result show I typed "git" 1530 times. So I can reduce 1530 * 2 = 3060 types by typing "g" instead of "git".
40
+
41
+
42
+ Todo:
43
+
44
+ * It can parse other shell scrpt(bash, csh, etc...)
45
+ * Add the function that recommends alias that can reduce your types by setting it
46
+ * Add the function that show Gold Standard
47
+ * Acceleration
48
+
49
+
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.ruby_opts = '-w'
6
+ end
7
+
8
+ task :default => :spec
9
+ rescue LoadError
10
+ raise 'RSpec could not be loaded. Run `bundle install` to get all development dependencies.'
11
+ end
@@ -0,0 +1,13 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = 'alias_metrics'
3
+ spec.version = '0.1'
4
+ spec.summary = "This tool is to visualize alias usage to parse command history. You can evaluate whether you use alias efficiently or not."
5
+ spec.author = ["Kohei Tomita"]
6
+ spec.email = "tommy.fmale@gmail.com"
7
+ spec.executables = %w(alias_metrics)
8
+ spec.files = `git ls-files`.split("\n") rescue ''
9
+ spec.homepage = "https://github.com/tomity/alias_metrics"
10
+ spec.add_development_dependency 'rspec', '~> 2.0'
11
+ spec.add_development_dependency 'fuubar', "~> 1.0.0"
12
+ spec.add_development_dependency "rake", "~> 0.9.2.2"
13
+ end
data/bin/alias_metrics ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ lib = File.dirname(__FILE__) + '/../lib/'
3
+ $:.unshift lib unless $:.include?(lib)
4
+ require "alias_metrics"
5
+
6
+ @alias_list = AliasList.load_from_stdin
7
+ @history = CommandHistory.load_from_zsh_history(@alias_list)
8
+ command_length_all = @history.commands.map{|command| command.size}.inject(0){|partial_sum, size| partial_sum + size}
9
+ shorten_count = @history.shorten_count
10
+ shorten_rate = shorten_count.to_f / command_length_all
11
+ shortenable_count_all = @history.shortenables.values.inject(0){|partial_sum, shortenable| partial_sum + shortenable.count * [0, (shortenable.command.size - shortenable.alias.size)].max }
12
+ shortenable_rate = shortenable_count_all.to_f / command_length_all
13
+
14
+ puts "You reduce #{sprintf("%0.2f", shorten_rate * 100)}% types (#{shorten_count} types/ #{command_length_all} types)"
15
+ puts "If you use alias all, you can reduce more #{sprintf("%0.2f", shortenable_rate * 100)}% types (#{shortenable_count_all} types / #{command_length_all} types)"
16
+ puts
17
+
18
+ puts "You often forget the following alias"
19
+ puts "alias\t#used\t#forgot\tforgot rate(%)\tcommand"
20
+ keys = @history.shortenables.keys.sort{|a, b| @history.shortenables[a].count <=> @history.shortenables[b].count }.reverse
21
+ keys.each do |key|
22
+ shortenable = @history.shortenables[key]
23
+ alias_usage = @history.alias_usages[shortenable.alias]
24
+ forgot_rate = shortenable.count.to_f / (alias_usage.count + shortenable.count)
25
+ puts "#{shortenable.alias}\t#{alias_usage.count}\t#{shortenable.count}\t#{sprintf("%0.2f", forgot_rate*100)}\t#{shortenable.command}"
26
+ end
27
+
Binary file
@@ -0,0 +1,4 @@
1
+ require "alias_metrics/alias_list.rb"
2
+ require "alias_metrics/alias_usage.rb"
3
+ require "alias_metrics/command_history.rb"
4
+ require "alias_metrics/shortenable.rb"
@@ -0,0 +1,89 @@
1
+ class AliasList
2
+ attr_accessor :alias_hash
3
+
4
+ def self.load_from_lines(lines)
5
+ alias_hash = Hash::new
6
+ lines.each do |line|
7
+ key, value = separate_key_value_from_alias_line(line)
8
+ alias_hash[key] = value
9
+ end
10
+ AliasList.new(alias_hash)
11
+ end
12
+
13
+ def self.load_from_stdin
14
+ alias_hash = Hash::new
15
+ STDIN.each do |line|
16
+ line.chomp!
17
+ key, value = separate_key_value_from_alias_line(line)
18
+ alias_hash[key] = value
19
+ end
20
+ AliasList.new(alias_hash)
21
+ end
22
+
23
+ #NOTE: Since #command >> #alias, this process do fastly
24
+ def expand_command(command)
25
+ @alias_hash.each_pair do |key, value|
26
+ if used_subcommand?(command, key)
27
+ command = command.sub(key, value)
28
+ end
29
+ end
30
+ command
31
+ end
32
+
33
+ #NOTE: Since #command >> #alias, this process do fastly
34
+ def applied_alias(command)
35
+ ret = []
36
+ @alias_hash.each_pair do |key, value|
37
+ if used_subcommand?(command, key)
38
+ command = command.sub(key, value)
39
+ ret << [key, value]
40
+ end
41
+ end
42
+ ret
43
+ end
44
+
45
+ #NOTE: Since #command >> #alias, this process do fastly
46
+ def shortenable?(command)
47
+ @alias_hash.values.each do |value|
48
+ if used_subcommand?(command, value)
49
+ return true
50
+ end
51
+ end
52
+ false
53
+ end
54
+
55
+ def shortenable_alias(command)
56
+ ret = []
57
+ @alias_hash.each_pair do |key, value|
58
+ if used_subcommand?(command, value)
59
+ ret << [key, value]
60
+ end
61
+ end
62
+ ret
63
+ end
64
+
65
+ private
66
+
67
+ def initialize(alias_hash)
68
+ @alias_hash = alias_hash.freeze
69
+ end
70
+
71
+ def self.separate_key_value_from_alias_line(line)
72
+ key, value = line.split(/=/)
73
+ value = remove_single_quotes(value)
74
+ [key, value]
75
+ end
76
+
77
+ def self.remove_single_quotes(value)
78
+ if value[0, 1] == "'" and value[-1, 1] == "'"
79
+ value = value[1..-2]
80
+ end
81
+ value
82
+ end
83
+
84
+ def used_subcommand?(command, alias_)
85
+ command == alias_ || command.start_with?(alias_+ " ")
86
+ end
87
+ end
88
+
89
+
@@ -0,0 +1,13 @@
1
+
2
+ class AliasUsage
3
+ attr_accessor :alias
4
+ attr_accessor :command
5
+ attr_accessor :count
6
+
7
+ def initialize(alias_, command)
8
+ self.alias = alias_.freeze
9
+ self.command = command.freeze
10
+ self.count = 0
11
+ end
12
+
13
+ end
@@ -0,0 +1,79 @@
1
+ class CommandHistory
2
+ attr_accessor :commands
3
+ attr_accessor :shorten_count
4
+ attr_accessor :shortenables
5
+ attr_accessor :alias_usages
6
+ attr_accessor :alias_list
7
+
8
+ ZSH_HISTORY_FILE = "#{ENV["HOME"]}/.zsh_history"
9
+
10
+ def initialize(commands, alias_list)
11
+ self.alias_list = alias_list
12
+ self.commands = []
13
+ self.shorten_count = 0
14
+ self.shortenables = Hash.new
15
+ self.alias_usages = Hash.new
16
+ alias_list.alias_hash.each_pair do |alias_, value|
17
+ self.alias_usages[alias_] = AliasUsage.new(alias_, value)
18
+ self.shortenables[value] = Shortenable.new(alias_, value)
19
+ end
20
+
21
+ commands.each do |command|
22
+ update_shortenables(command)
23
+ update_alias_usages(command)
24
+ command_expanded = self.alias_list.expand_command(command)
25
+ self.shorten_count += [0, command_expanded.length - command.length].max
26
+ self.commands << command_expanded
27
+ end
28
+ self.alias_list = self.alias_list.freeze
29
+ self.commands = self.commands.freeze
30
+ self.shorten_count = self.shorten_count.freeze
31
+ self.shortenables = self.shortenables.freeze
32
+ self.alias_usages = self.alias_usages.freeze
33
+ end
34
+
35
+ def self.load_from_zsh_history(alias_list, history_file = ZSH_HISTORY_FILE)
36
+ commands = []
37
+ open(history_file) do |fh|
38
+ fh.each do |line|
39
+ line.chomp!
40
+ next if line == ""
41
+ begin
42
+ command = parse_command_by_zsh_history_line(line)
43
+ commands << command if command
44
+ rescue ArgumentError #invalid byte sequence in UTF-8
45
+ #do nothing
46
+ end
47
+ end
48
+ end
49
+ CommandHistory.new(commands, alias_list)
50
+ end
51
+
52
+ private
53
+
54
+ def self.parse_command_by_zsh_history_line(line)
55
+ command = line.split(/;/)[1]
56
+ return command
57
+ end
58
+
59
+ def update_shortenables(command)
60
+ if alias_list.shortenable?(command)
61
+ shortenable_alias_list = alias_list.shortenable_alias(command)
62
+ shortenable_alias_list.each do |alias_, extension|
63
+ self.shortenables[extension].count += 1 if shortenable?(alias_, extension)
64
+ end
65
+ end
66
+ end
67
+
68
+ def update_alias_usages(command)
69
+ applied_alias = self.alias_list.applied_alias(command)
70
+ applied_alias.each do |alias_, value|
71
+ self.alias_usages[alias_].count += 1
72
+ end
73
+ end
74
+
75
+ def shortenable?(alias_, command)
76
+ command.size > alias_.size
77
+ end
78
+
79
+ end
@@ -0,0 +1,11 @@
1
+ class Shortenable
2
+ attr_accessor :command
3
+ attr_accessor :alias
4
+ attr_accessor :count
5
+
6
+ def initialize(alias_, command)
7
+ self.alias = alias_.freeze
8
+ self.command = command.freeze
9
+ self.count = 0
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ require "alias_metrics"
2
+
3
+ describe AliasList do
4
+ before do
5
+ @alias_list = AliasList.load_from_lines(["l='ls -la'", "sl=ls", "grhh='git reset --hard HEAD\^'"])
6
+ end
7
+ describe "expand_command" do
8
+ it "should output `ls -la` for the command `l` " do
9
+ @alias_list.expand_command("l").should == "ls -la"
10
+ end
11
+
12
+ it "should output `ls -la -h` for the command `l -h` " do
13
+ @alias_list.expand_command("l -h").should == "ls -la -h"
14
+ end
15
+
16
+ it "should output `ls` for the command `sl` " do
17
+ @alias_list.expand_command("sl").should == "ls"
18
+ end
19
+
20
+ it "should output `ls -l` for the command `sl -l` " do
21
+ @alias_list.expand_command("sl -l").should == "ls -l"
22
+ end
23
+
24
+ it "should output `slope` for the command `slope` because this command is slope, but is not sl" do
25
+ @alias_list.expand_command("slope").should == "slope"
26
+ end
27
+ end
28
+
29
+ describe "shortenable" do
30
+ it "should output `ls -la` is shortenable" do
31
+ @alias_list.shortenable?("ls -la").should == true
32
+ end
33
+
34
+ it "should output `ls -la -h` for the command `l -h` " do
35
+ @alias_list.shortenable?("ls -la -h").should == true
36
+ end
37
+
38
+ it "should output `git reset --hard` is not shortenable" do
39
+ @alias_list.shortenable?("git reset --hard").should == false
40
+ end
41
+
42
+ it "should output `git HEAD\^ --hard` is not shortenable" do #Is this specification correct?
43
+ @alias_list.shortenable?("git reset HEAD\^ --hard").should == false
44
+ end
45
+ end
46
+
47
+ end
48
+
49
+
50
+
@@ -0,0 +1,70 @@
1
+ require "alias_metrics"
2
+
3
+ describe CommandHistory do
4
+ before do
5
+ @alias_list = AliasList.load_from_lines(["l='ls -la'", "ga=git add", "run-help=man"])
6
+ @history = CommandHistory.new(["l", "l -h", "ls -la", "ls -la -h", "man"], @alias_list)
7
+ end
8
+
9
+ it "can get the number of commands" do
10
+ @history.commands.size.should == 5
11
+ end
12
+
13
+ it "can count the number of chars shorten" do
14
+ @history.shorten_count.should == 10 #becaulse (`ls -la` => `l`) * 2
15
+ end
16
+
17
+ it "should be count is 2 when ls -la" do
18
+ shortenable = @history.shortenables["ls -la"]
19
+ shortenable.alias.should == "l"
20
+ shortenable.command.should == "ls -la"
21
+ shortenable.count.should == 2
22
+ end
23
+
24
+ it "should be count is 0 when git add" do
25
+ shortenable = @history.shortenables["git add"]
26
+ shortenable.alias.should == "ga"
27
+ shortenable.command.should == "git add"
28
+ shortenable.count.should == 0
29
+ end
30
+
31
+ it "should be count is 0 when ls -la because run-help is longer than man" do
32
+ shortenable = @history.shortenables["man"]
33
+ shortenable.alias.should == "run-help"
34
+ shortenable.command.should == "man"
35
+ shortenable.count.should == 0
36
+ end
37
+
38
+ it "should be alias usage is 2 when l" do
39
+ alias_usage = @history.alias_usages["l"]
40
+ alias_usage.alias.should == "l"
41
+ alias_usage.command.should == "ls -la"
42
+ alias_usage.count.should == 2
43
+ end
44
+
45
+ it "should be alias usage is 0 when ga" do
46
+ alias_usage = @history.alias_usages["ga"]
47
+ alias_usage.alias.should == "ga"
48
+ alias_usage.command.should == "git add"
49
+ alias_usage.count.should == 0
50
+ end
51
+
52
+ it "should be alias usage is 0 when run-help" do
53
+ alias_usage = @history.alias_usages["run-help"]
54
+ alias_usage.alias.should == "run-help"
55
+ alias_usage.command.should == "man"
56
+ alias_usage.count.should == 0
57
+ end
58
+
59
+ it "can load from ~/.zsh_history" do
60
+ CommandHistory.load_from_zsh_history(@alias_list)
61
+ end
62
+
63
+ it "should store expanded commands" do
64
+ @history.commands[0].should == "ls -la"
65
+ @history.commands[1].should == "ls -la -h"
66
+ @history.commands[2].should == "ls -la"
67
+ @history.commands[3].should == "ls -la -h"
68
+ @history.commands[4].should == "man"
69
+ end
70
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: alias_metrics
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kohei Tomita
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: &2152591180 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *2152591180
25
+ - !ruby/object:Gem::Dependency
26
+ name: fuubar
27
+ requirement: &2152590180 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: 1.0.0
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2152590180
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &2152608520 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: 0.9.2.2
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2152608520
47
+ description:
48
+ email: tommy.fmale@gmail.com
49
+ executables:
50
+ - alias_metrics
51
+ extensions: []
52
+ extra_rdoc_files: []
53
+ files:
54
+ - .gitignore
55
+ - .rspec
56
+ - Gemfile
57
+ - Gemfile.lock
58
+ - README
59
+ - Rakefile
60
+ - alias_metrics.gemspec
61
+ - bin/alias_metrics
62
+ - gems/alias_metrics-0.1.gem
63
+ - lib/alias_metrics.rb
64
+ - lib/alias_metrics/alias_list.rb
65
+ - lib/alias_metrics/alias_usage.rb
66
+ - lib/alias_metrics/command_history.rb
67
+ - lib/alias_metrics/shortenable.rb
68
+ - spec/alias_list_spec.rb
69
+ - spec/command_history_spec.rb
70
+ homepage: https://github.com/tomity/alias_metrics
71
+ licenses: []
72
+ post_install_message:
73
+ rdoc_options: []
74
+ require_paths:
75
+ - lib
76
+ required_ruby_version: !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ! '>='
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 1.8.10
91
+ signing_key:
92
+ specification_version: 3
93
+ summary: This tool is to visualize alias usage to parse command history. You can evaluate
94
+ whether you use alias efficiently or not.
95
+ test_files: []