shepherd 0.1.0 → 0.1.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.
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .yardoc/*
6
+ spec/*
data/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # shepherd 0.1.2 (18-07-2011)
2
+
3
+ + Make the `Counter` class
4
+ + The `init` command works-but-not-really - it's not saving projects at the moment
5
+ + Provide `Db` connector
6
+
7
+ # shepherd 0.1.1 (04-07-2011)
8
+
9
+ + Ease in creating your own commands!
10
+ + Let be t'e `Cli`!
11
+
12
+ # shepherd 0.1.0 (18-06-2011)
13
+
14
+ + Birthday!
data/Gemfile CHANGED
@@ -1,13 +1,3 @@
1
- source "http://rubygems.org"
2
- # Add dependencies required to use your gem here.
3
- # Example:
4
- # gem "activesupport", ">= 2.3.5"
1
+ source :gemcutter
5
2
 
6
- # Add dependencies to develop your gem here.
7
- # Include everything needed to run rake, tests, features, etc.
8
- group :development do
9
- gem "shoulda", ">= 0"
10
- gem "bundler", "~> 1.0.0"
11
- gem "jeweler", "~> 1.6.1"
12
- gem "rcov", ">= 0"
13
- end
3
+ gemspec
data/README.md CHANGED
@@ -1,13 +1,40 @@
1
- # Shepherd
1
+ Shepherd
2
+ ========
2
3
 
3
- **Homepage** [http://semahawk.github.com/shepherd](http://semahawk.github.com/shepherd)
4
- **Author** Szymon Urbaś <szymon.urbas@yahoo.com>
5
- **Copyright** 2011
6
- **License** MIT License
7
-
8
- **Latest version** 0.1.0
9
- **Stage** *Development*
10
- **Release date** June 9th, 2011
4
+ <table>
5
+ <tr>
6
+ <td><b>Homepage</b></td>
7
+ <td><a href="http://semahawk.github.com/shepherd">http://semahawk.github.com/shepherd</a></td>
8
+ </tr>
9
+ <tr>
10
+ <td><b>Author</b></td>
11
+ <td>Szymon Urbaś (szymon dot urbas at yahoo dot com)</td>
12
+ </tr>
13
+ <tr>
14
+ <td><b>Copyright</b></td>
15
+ <td>2011</td>
16
+ </tr>
17
+ <tr>
18
+ <td><b>License</b></td>
19
+ <td>MIT</td>
20
+ </tr>
21
+ <tr>
22
+ <td> </td>
23
+ <td> </td>
24
+ </tr>
25
+ <tr>
26
+ <td><b>Latest version</b></td>
27
+ <td>0.1.1</td>
28
+ </tr>
29
+ <tr>
30
+ <td><b>Release date</b></td>
31
+ <td>July 4th, 2011</td>
32
+ </tr>
33
+ <tr>
34
+ <td><b>Stage</b></td>
35
+ <td><i>Development</i></td>
36
+ </tr>
37
+ </table>
11
38
 
12
39
  ## A bit about
13
40
 
@@ -16,13 +43,13 @@ You just know, if your project got few kilobytes more on weight, how many more f
16
43
 
17
44
  ## Features
18
45
 
19
- * Existence, at the moment :D
46
+ + Easy own command creation.
47
+
48
+ ## Dependencies
20
49
 
21
- But the ideas are:
50
+ + [sqlite3](http://rubygems.org/gems/sqlite3) (~> 1.3.0)
22
51
 
23
- * Files, lines and characters counting
24
- * Uh.. Emm...
25
- * Yeah..
52
+ Shepherd also uses `cat` and `wc` UNIX commands, so if you are on UNIX(-like) system there should be no problem.
26
53
 
27
54
  ## Oh, NO - a BUG!
28
55
 
data/Rakefile CHANGED
@@ -1,54 +1 @@
1
- # encoding: utf-8
2
-
3
- require 'rubygems'
4
- require 'bundler'
5
- begin
6
- Bundler.setup(:default, :development)
7
- rescue Bundler::BundlerError => e
8
- $stderr.puts e.message
9
- $stderr.puts "Run `bundle install` to install missing gems"
10
- exit e.status_code
11
- end
12
- require 'rake'
13
-
14
- require 'jeweler'
15
- require './lib/shepherd/version'
16
- Jeweler::Tasks.new do |gem|
17
- gem.name = "shepherd"
18
- gem.homepage = "http://github.com/semahawk/shepherd"
19
- gem.license = "MIT"
20
- gem.summary = %Q{Be a shepherd to your projects!}
21
- gem.description = %Q{*BETA* Be a shepherd to your projects! Check out whether they grow up, get larger or something-else-shepherds-do!}
22
- gem.version = Shepherd::Version::STRING
23
- gem.email = "szymon.urbas@yahoo.com"
24
- gem.authors = ["Szymon Urbaś"]
25
- # dependencies defined in Gemfile
26
- end
27
- Jeweler::RubygemsDotOrgTasks.new
28
-
29
- require 'rake/testtask'
30
- Rake::TestTask.new(:test) do |test|
31
- test.libs << 'lib' << 'test'
32
- test.pattern = 'test/**/test_*.rb'
33
- test.verbose = true
34
- end
35
-
36
- require 'rcov/rcovtask'
37
- Rcov::RcovTask.new do |test|
38
- test.libs << 'test'
39
- test.pattern = 'test/**/test_*.rb'
40
- test.verbose = true
41
- test.rcov_opts << '--exclude "gems/*"'
42
- end
43
-
44
- task :default => :test
45
-
46
- require 'rake/rdoctask'
47
- Rake::RDocTask.new do |rdoc|
48
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
49
-
50
- rdoc.rdoc_dir = 'rdoc'
51
- rdoc.title = "shepherd #{version}"
52
- rdoc.rdoc_files.include('README*')
53
- rdoc.rdoc_files.include('lib/**/*.rb')
54
- end
1
+ require 'bundler/gem_tasks'
data/bin/shep ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ # Add the lib directory to $LOAD_PATH
5
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
6
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
7
+
8
+ # Require needed files
9
+ require 'shepherd'
10
+ require 'shepherd/cli'
11
+
12
+ # We make the --help option the default (if no command passed, show help)
13
+ ARGV << '--help' if ARGV.empty? && $stdin.tty?
14
+
15
+ # Run Shepherd, ruuun!
16
+ Shepherd::Cli.new.run!
@@ -0,0 +1,121 @@
1
+ require "trollop"
2
+
3
+ module Shepherd
4
+
5
+ # Command Line Interface class
6
+ class Cli
7
+
8
+ # Kinda self explanatory
9
+ class UnknownCommand < RuntimeError; end
10
+
11
+ # A command which is about to be run
12
+ attr_accessor :command
13
+
14
+ # Require *all* command files
15
+ Dir[File.join(File.dirname(__FILE__), "commands", "*.rb")].each do |all_command_files|
16
+ require all_command_files
17
+ end
18
+
19
+ # Handle the commands list
20
+ #
21
+ # @return [Array] all available commands
22
+ COMMANDS = Command.constants.select { |c| Class === Command.const_get(c) }
23
+
24
+ # Get a list of available commands to be printed. (Almost) every line is separated by new line mark - \n
25
+ #
26
+ # @return [String] list of all available commands
27
+ def commands_list
28
+ out = ""
29
+ # If there are no commands set
30
+ if COMMANDS.empty?
31
+ out << " ooops! commands are not here!"
32
+ else
33
+ # Get the longest command's name, so we can output it nice 'n' clean
34
+ # This '+ int' at the end is a distance (in spaces) from the longest
35
+ # command to descriptions
36
+ longest = COMMANDS.max_by(&:size).size + 8
37
+ COMMANDS.each do |cmd|
38
+ # Calc, calc.
39
+ spaces = longest - cmd.size
40
+ # Check if there is a 'desc' method
41
+ desc = if eval "Command::#{cmd}.new.respond_to? 'desc'"
42
+ # If there is - execute it
43
+ eval "Command::#{cmd}.new.desc"
44
+ else
45
+ # If there is not
46
+ "~ no description provided ~"
47
+ end
48
+ out << " " << cmd.downcase.to_s << " " * spaces << desc
49
+ # If this command is the last one, don't make a new line
50
+ unless cmd == COMMANDS.last
51
+ out << "\n"
52
+ end
53
+ end
54
+ end
55
+ out
56
+ end
57
+
58
+ # Check if command really exists
59
+ #
60
+ # @return [Boolean] whether the command exists or not
61
+ def command_exists?
62
+ COMMANDS.include? @command
63
+ end
64
+
65
+ # Rruns t'e Cli!
66
+ def run!
67
+
68
+ # Nice, cool 'n' AWESOME --options parsing with Trollop[http://trollop.rubyforge.org/]!
69
+ #
70
+ # @return [Hash] array full of options
71
+ $opts = Trollop::options do
72
+ version "Shepherd be t'e version #{Version::STRING}"
73
+ banner <<-EOB
74
+ usage: shep [options] <command>
75
+
76
+ commands are:
77
+
78
+ #{Cli.new.commands_list}
79
+
80
+ shep <command> --help for more info about specified command
81
+
82
+ options are:
83
+ EOB
84
+
85
+ opt :version, "show version and exit", :short => '-v'
86
+ opt :help, "show me and exit", :short => '-h'
87
+
88
+ stop_on COMMANDS.collect { |e| e.downcase.to_s }
89
+ end
90
+
91
+ # Get the command
92
+ @command = ARGV.shift.capitalize.to_sym
93
+
94
+ begin
95
+ execute @command
96
+ exit 0
97
+ rescue UnknownCommand => e
98
+ puts e.message
99
+ exit 1
100
+ rescue Db::DatabaseNotFound => e
101
+ puts e.message
102
+ exit 1
103
+ rescue Interrupt
104
+ puts "\n\n~> interrupted"
105
+ exit 1
106
+ end
107
+ end # run!:Method
108
+
109
+ # Executes a command
110
+ #
111
+ # @return [Object] command to execute
112
+ # @raise [UnknownCommand] if there is no such a command
113
+ def execute command
114
+ if command_exists?
115
+ eval "Command::#{command}.new.init"
116
+ else
117
+ raise UnknownCommand, "Error: unknown command '#{command.downcase.to_s}'.\nTry --help for help."
118
+ end
119
+ end # execute_command:Method
120
+ end # Cli:Class
121
+ end # Shepherd:Module
@@ -0,0 +1,65 @@
1
+ module Shepherd
2
+
3
+ # A (actually, very) simple class, which is used to determine whether is this class a command, or not.
4
+ #
5
+ # == Creating a command
6
+ # A Shepherd's command is just a class, which is kept inside +Shepherd::Command+.
7
+ # Just create a ruby file inside +lib/shepherd/commands/+ called however you like, eg. foo.rb.
8
+ # This file should look kinda like this stuff:
9
+ #
10
+ # module Shepherd::Command
11
+ # class Foobar # this is the commands name; that would be: shep foobar
12
+ # def init # when you call: shep <command>, init method here is executed.
13
+ # puts "foobarinize!"
14
+ # end
15
+ # end
16
+ # end
17
+ #
18
+ # You can also specify some other method than +init+ (eg. ahoy) and then use an +alias+ method:
19
+ #
20
+ # module Shepherd::Command
21
+ # class Pirate
22
+ # def ahoy
23
+ # puts "Ahoy, aad'enturre!"
24
+ # end
25
+ # alias :init :ahoy
26
+ # end
27
+ # end
28
+ #
29
+ # == Options parsing
30
+ # For --options parsing, Shepherd uses Trollop[http://trollop.rubyforge.org/] (which by the way is AWESOME!):
31
+ #
32
+ # module Shepherd::Command
33
+ # class Foobar
34
+ # def init
35
+ # opts = Trollop::options do
36
+ # opt :monkey, "Use monkey mode" # flag --monkey, default false
37
+ # opt :goat, "Use goat mode", :default => true # flag --goat, default true
38
+ # opt :num_limbs, "Number of limbs", :default => 4 # integer --num-limbs <i>, default to 4
39
+ # opt :num_thumbs, "Number of thumbs", :type => :int # integer --num-thumbs <i>, default nil
40
+ # end
41
+ # end
42
+ # end
43
+ # end
44
+ #
45
+ # You can of course use for example +OptionParser+, if you want. But.. Trollop[http://trollop.rubyforge.org/] is AWESOME! THAT's why wise Shepherd is using it ;)
46
+ #
47
+ # == Multiple commands
48
+ # Also, yau can create more than one command inside one file:
49
+ #
50
+ # module Shepherd::Command
51
+ # class Foobar
52
+ # def init
53
+ # puts "foobarinize!"
54
+ # end
55
+ # end
56
+ #
57
+ # class Barbaz
58
+ # def init
59
+ # puts "barbazinize!"
60
+ # end
61
+ # end
62
+ # end
63
+ #
64
+ module Command; end
65
+ end
@@ -0,0 +1,51 @@
1
+ module Shepherd::Command
2
+ class Init
3
+ def init
4
+ @opts = Trollop::options do
5
+ banner <<-EOB
6
+ usage: shep [options] init [-h|--help]
7
+
8
+ options are:
9
+ EOB
10
+ opt :path, "a root path to the project", :default => Dir.pwd
11
+ opt :name, "set a projects name (default: a top directory name from --path will be taken)", :type => :string
12
+ opt :quiet, "don't show what's going on"
13
+ opt :help, "show me and exit", :short => '-h'
14
+ end
15
+
16
+ @state = {}
17
+ # delete the last '/' in path if present
18
+ @state[:path] = @opts[:path].chomp "/"
19
+ # use this top directory name unless --name is set
20
+ @state[:name] = @opts[:name] ? @opts[:name] : @opts[:path].split("/").last
21
+
22
+ Shepherd::Counter.new(@state[:path]) do |count|
23
+ @state[:files] = count.files
24
+ @state[:lines] = count.lines
25
+ @state[:chars] = count.chars
26
+ @state[:bytes] = count.bytes
27
+ @state[:rawbytes] = count.rawbytes
28
+ end
29
+
30
+ puts "Our brave-hearted Shepherd initializes a new project!
31
+
32
+ path: \e[1;34m#{@state[:path]}\e[0;0m
33
+ name: \e[1;32m#{@state[:name]}\e[0;0m
34
+
35
+ state: #{@state[:files].size} files
36
+ #{@state[:lines]} lines
37
+ #{@state[:chars]} chars
38
+
39
+ #{@state[:bytes]} (#{@state[:rawbytes]} bytes)
40
+
41
+ " unless @opts[:quiet]
42
+
43
+ # TODO: save to database
44
+ # Shepherd::Db.new.execute "inserting query"
45
+ end
46
+
47
+ def desc
48
+ "initialize a new project"
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,140 @@
1
+ require "find"
2
+
3
+ module Shepherd
4
+
5
+ # A simple class that counts all the needed data (like files, lines, bytes and so-on) in given destination path.
6
+ #
7
+ # == Usage
8
+ #
9
+ # Without using a block:
10
+ # module Shepherd
11
+ # count = Counter.new(/path/to/destination/dir)
12
+ # count.files #=> 26
13
+ # count.lines #=> 2319
14
+ # count.chars #=> 79240
15
+ # end
16
+ #
17
+ # With a block:
18
+ # module Shepherd
19
+ # Counter.new(/path/to/destination/dir) do |count|
20
+ # count.files #=> 26
21
+ # count.lines #=> 2319
22
+ # count.chars #=> 79240
23
+ # end
24
+ # end
25
+ #
26
+ # Inside a +Shepherd::Command::Klass+ you should use it like so:
27
+ # module Shepherd::Command
28
+ # class Klass
29
+ # Shepherd::Counter.new(/path/to/destination/dir) do |count|
30
+ # count.files #=> 26
31
+ # count.lines #=> 2319
32
+ # count.chars #=> 79240
33
+ # end
34
+ # end
35
+ # end
36
+ #
37
+ # @return [Shepherd::Counter] a new instance of +Shepherd::Counter+
38
+ # @yield [Shepherd::Counter] a new instance of +Shepherd::Counter+
39
+ #
40
+ class Counter
41
+ # A new instance of +Shepherd::Counter+
42
+ #
43
+ # @param [String] path a path to the project
44
+ # @return [Shepherd::Counter] a new instance of +Shepherd::Counter+
45
+ # @yield [Shepherd::Counter] a new instance of +Shepherd::Counter+
46
+ def initialize path
47
+ # delete the last '/' in path if present, just to make sure :)
48
+ @path = path.chomp "/"
49
+
50
+ yield self if block_given?
51
+ end
52
+
53
+ # Convert bytes into more human readable format.
54
+ # Found nice resolution here[http://www.ruby-forum.com/topic/119703] which was originally written by {Jeff Emminger}[http://www.ruby-forum.com/user/show/jemminger] and I just add this part to automaticly set the unit. Thank you!
55
+ #
56
+ # @param [Integer] number a number to be formatted
57
+ # @return [String] a formatted number
58
+ def nice_bytes number
59
+ units = {:b => 1,
60
+ :kb => 2**10,
61
+ :mb => 2**20,
62
+ :gb => 2**30,
63
+ :tb => 2**40}
64
+
65
+ unit = :b
66
+ case number
67
+ when 1...2**10
68
+ unit = :b
69
+ when 2**10...2**20
70
+ unit = :kb
71
+ when 2**20...2**30
72
+ unit = :mb
73
+ when 2**30...2**40
74
+ unit = :gb
75
+ when 2**40...2**50
76
+ unit = :tb
77
+ end
78
+ "#{sprintf("%.#{0}f", number / units[unit.to_s.downcase.to_sym])} #{unit.to_s.upcase}"
79
+ end
80
+
81
+ # Count the files (excluding dotfiles).
82
+ #
83
+ # @return [Array] list of all files (dotfiles are not included)
84
+ def files
85
+ @files = []
86
+ Find.find(@path) do |path|
87
+ if File.directory? path
88
+ if File.basename(path)[0] == ?.
89
+ Find.prune # don't look any further into this directory.
90
+ else
91
+ next
92
+ end
93
+ else
94
+ @files << path
95
+ end
96
+ end
97
+ @files
98
+ end
99
+
100
+ # Count the lines.
101
+ #
102
+ # @return [Integer] lines amount
103
+ def lines
104
+ @lines = 0
105
+ @files.each do |file|
106
+ @lines += `cat '#{file}' | wc -l`.to_i
107
+ end
108
+ @lines
109
+ end
110
+
111
+ # Count the characters.
112
+ #
113
+ # @return [Integer] characters amount
114
+ def chars
115
+ @chars = 0
116
+ @files.each do |file|
117
+ @chars += `cat '#{file}' | wc -m`.to_i
118
+ end
119
+ @chars
120
+ end
121
+
122
+ # Count the bytes. This *wont* be converted all the time.
123
+ #
124
+ # @return [Integer] bytes amount
125
+ def rawbytes
126
+ @rawbytes = 0
127
+ @files.each do |file|
128
+ @rawbytes += File.new("#{file}").size
129
+ end
130
+ @rawbytes
131
+ end
132
+
133
+ # Count the bytes. This *will* be formatted into something like: 2898 KB
134
+ #
135
+ # @return [String] formatted bytes
136
+ def bytes
137
+ @bytes = nice_bytes rawbytes
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,40 @@
1
+ require "sqlite3"
2
+
3
+ module Shepherd
4
+
5
+ # A class through which you can connect to the database.
6
+ #
7
+ # == Usage
8
+ #
9
+ # module Shepherd
10
+ # Db.new.execute "sql query"
11
+ # end
12
+ #
13
+ # Inside a +Shepherd::Command::Klass+, it would look like:
14
+ #
15
+ # module Shepherd::Command
16
+ # class Klass
17
+ # def init
18
+ # Shepherd::Db.new.execute "sql query"
19
+ # end
20
+ # end
21
+ # end
22
+ #
23
+ # Here is {SQLite3 documantation}[http://sqlite-ruby.rubyforge.org/sqlite3/faq.html]. +Shepherd::Db.new+ is equal to +SQLite3::Database.new+ so there you've got a complete documentation.
24
+ #
25
+ class Db
26
+
27
+ # When the database file was not found
28
+ class DatabaseNotFound < RuntimeError; end
29
+
30
+ def initialize
31
+ raise DatabaseNotFound, "Error: database file not found: '#{Dir.home}/.shepherd/herd.db'\nTry running 'shep setup'." unless File.exists? "#{Dir.home}/.shepherd/herd.db"
32
+ # A new instance of +SQLite3::Database+
33
+ @db = SQLite3::Database.new "#{Dir.home}/.shepherd/herd.db"
34
+ end
35
+
36
+ def method_missing m, *args, &block
37
+ @db.send m, *args, &block
38
+ end
39
+ end
40
+ end
@@ -1,10 +1,10 @@
1
1
  module Shepherd
2
- module Version
3
- MAJOR = 0
4
- MINOR = 1
5
- PATCH = 0
6
- BUILD = nil
2
+ module Version
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ PATCH = 2
6
+ BUILD = nil
7
7
 
8
- STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join "."
9
- end
8
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join "."
9
+ end
10
10
  end
data/lib/shepherd.rb CHANGED
@@ -0,0 +1,9 @@
1
+ module Shepherd
2
+ ROOT = File.expand_path(File.dirname(__FILE__))
3
+
4
+ autoload :Command, "#{ROOT}/shepherd/command"
5
+ autoload :Counter, "#{ROOT}/shepherd/counter"
6
+ autoload :Db, "#{ROOT}/shepherd/db"
7
+ autoload :Cli, "#{ROOT}/shepherd/cli"
8
+ autoload :Version, "#{ROOT}/shepherd/version"
9
+ end