mm 0.2.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.
File without changes
data/bin/mm ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "#{File.dirname(__FILE__)}/../lib/turbine"
5
+
6
+ Turbine::Application.new.run(ARGV.map { |e| e.dup })
@@ -0,0 +1,9 @@
1
+ Dir["#{Turbine::Application.config_dir}/commands/standard/*.rb"].each do |extension|
2
+ require extension
3
+ end
4
+
5
+ Dir["#{Turbine::Application.config_dir}/commands/custom/*.rb"].each do |extension|
6
+ require extension
7
+ end
8
+
9
+ Turbine::Application.api_key = "<%= key %>"
@@ -0,0 +1,7 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+
3
+ require "turbine/timer"
4
+ require "turbine/queue"
5
+ require "turbine/commands/init"
6
+ require "turbine/command_runner"
7
+ require "turbine/application"
@@ -0,0 +1,85 @@
1
+ require "pathname"
2
+ require "highline"
3
+ require "restclient"
4
+ require "json"
5
+
6
+ module Turbine
7
+ class Application
8
+
9
+ class << self
10
+ def config_dir(dir = Pathname.new("."))
11
+ turbine_dir = dir + ".turbine"
12
+ if dir.children.include?(turbine_dir)
13
+ turbine_dir.expand_path
14
+ else
15
+ return nil if dir.expand_path.root?
16
+ config_dir(dir.parent)
17
+ end
18
+ end
19
+
20
+ def extensions
21
+ @extensions ||= []
22
+ end
23
+
24
+ def extension(&block)
25
+ extensions << Module.new(&block)
26
+ end
27
+
28
+ def current_project
29
+ File.read("#{config_dir}/current_project").chomp
30
+ end
31
+
32
+ def current_project=(project)
33
+ File.open("#{config_dir}/current_project", "w") { |f| f << project }
34
+ end
35
+
36
+ def current_project_url
37
+ projects[current_project]
38
+ end
39
+
40
+ def projects
41
+ JSON.parse(File.read("#{config_dir}/projects.json"))
42
+ end
43
+
44
+ attr_accessor :api_key
45
+ end
46
+
47
+ def initialize
48
+ @params = {}
49
+ @prompt = HighLine.new
50
+ @option_parser = OptionParser.new
51
+ @turbine_dir = nil
52
+ end
53
+
54
+ def read_file(name)
55
+ File.read("#{self.class.config_dir}/#{name}")
56
+ end
57
+
58
+ def write_file(name, mode="w")
59
+ File.open("#{self.class.config_dir}/#{name}", mode) { |f| yield(f) }
60
+ end
61
+
62
+ def delete_file(name)
63
+ rm_f "#{self.class.config_dir}/#{name}"
64
+ end
65
+
66
+ def service
67
+ RestClient::Resource.new(self.class.current_project_url, self.class.api_key, "")
68
+ end
69
+
70
+ def load_log_data
71
+ JSON.parse(File.read("#{self.class.config_dir}/log/#{self.class.api_key}.json"))
72
+ end
73
+
74
+ def clear_log_data
75
+ write_file("log/#{self.class.api_key}.json") do |f|
76
+ f << [].to_json
77
+ end
78
+ end
79
+
80
+ attr_accessor :params, :prompt, :option_parser, :command
81
+
82
+ include ::Turbine::CommandRunner
83
+ include ::Turbine::StandardCommands
84
+ end
85
+ end
@@ -0,0 +1,63 @@
1
+ module Turbine
2
+ module CommandRunner
3
+ def setup
4
+ end
5
+
6
+ def run(argv)
7
+ init_and_exit(*argv) if argv[0] == "init"
8
+
9
+ unless self.class.config_dir
10
+ prompt.say "Cannot find config file. Did you forget to run turbine init?"
11
+ return
12
+ end
13
+
14
+ require "#{self.class.config_dir}/config"
15
+
16
+ self.class.extensions.each do |extension|
17
+ extend(extension)
18
+ end
19
+
20
+ setup
21
+ parse_options(*argv)
22
+
23
+ if respond_to?(command)
24
+ send(command)
25
+ else
26
+ prompt.say("Unknown command: #{command}")
27
+ end
28
+
29
+ teardown
30
+ end
31
+
32
+ def init_and_exit(*argv)
33
+ setup
34
+ parse_options(*argv)
35
+ init
36
+ teardown
37
+ exit
38
+ end
39
+
40
+ def teardown
41
+ end
42
+
43
+ def parse_options(*argv)
44
+ option_parser.on("-t", "=HOURS", Float) do |hours|
45
+ params[:hours] = hours
46
+ end
47
+
48
+ option_parser.on("-m", "=MSG", String) do |msg|
49
+ params[:message] = msg
50
+ end
51
+
52
+ option_parser.on("-k", "=KEY", String) do |msg|
53
+ params[:api_key] = msg
54
+ end
55
+
56
+ command, *arguments = option_parser.parse(*argv)
57
+
58
+ self.command = command
59
+ params[:arguments] = arguments
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,42 @@
1
+ require "json"
2
+ require "erb"
3
+ require "fileutils"
4
+
5
+ module Turbine
6
+ module StandardCommands
7
+ include FileUtils
8
+
9
+ def init
10
+ mkdir_p(".turbine")
11
+ mkdir_p(".turbine/log")
12
+ mkdir_p(".turbine/commands")
13
+ mkdir_p(".turbine/commands/custom")
14
+
15
+ key = params[:api_key] || ENV['TURBINE_API_KEY']
16
+ url = params[:arguments][0]
17
+ project_name = params[:arguments][1] || "default"
18
+
19
+ raise if key.nil?
20
+
21
+ current_dir = File.dirname(__FILE__)
22
+
23
+ write_file("log/#{key}.json") { |f| f << [].to_json }
24
+
25
+ write_file("config.rb") do |f|
26
+ template = File.read("#{current_dir}/../../../data/config.rb.erb")
27
+ f << ERB.new(template).result(binding)
28
+ end
29
+
30
+ write_file("current_project") do |f|
31
+ f << project_name
32
+ end
33
+
34
+ write_file("projects.json") do |f|
35
+ f << { project_name => url }.to_json
36
+ end
37
+
38
+ cp_r("#{current_dir}/standard",
39
+ "#{self.class.config_dir}/commands/")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,8 @@
1
+ Turbine::Application.extension do
2
+ def add
3
+ hours = params[:arguments].first
4
+
5
+ queue = Turbine::Queue.new(self.class.config_dir)
6
+ queue << hours
7
+ end
8
+ end
@@ -0,0 +1,29 @@
1
+ Turbine::Application.extension do
2
+ def commit
3
+ if message = params[:message]
4
+ queue = Turbine::Queue.new
5
+ duration = queue.sum.to_s
6
+ timestamp = Time.now.utc.to_s
7
+
8
+ if queue.empty?
9
+ prompt.say "ERROR: No entries!"
10
+ exit
11
+ end
12
+
13
+ log_data = load_log_data
14
+
15
+ log_data << { :description => message,
16
+ :recorded_timestamp => timestamp,
17
+ :recorded_date => Date.today.to_s,
18
+ :hours => duration }
19
+
20
+ write_file("log/#{self.class.api_key}.json") { |f| f << log_data.to_json }
21
+
22
+ prompt.say "Committed time entry totaling #{duration} hrs"
23
+
24
+ queue.clear
25
+ else
26
+ prompt.say "You need to supply a message"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,9 @@
1
+ Turbine::Application.extension do
2
+ def drop
3
+ log_data = load_log_data
4
+
5
+ log_data.delete_at(params[:arguments].first.to_i)
6
+
7
+ write_file("log/#{self.class.api_key}.json") { |f| f << log_data.to_json }
8
+ end
9
+ end
@@ -0,0 +1,66 @@
1
+ Turbine::Application.extension do
2
+
3
+ def project
4
+ _list_projects || _manage_projects
5
+ end
6
+
7
+ private
8
+
9
+ def _list_projects
10
+ return false unless params[:arguments].empty?
11
+
12
+ prompt.say("\n")
13
+
14
+ self.class.projects.each do |name, url|
15
+ prompt.say(name == self.class.current_project ? " > " : " ")
16
+ prompt.say("#{name} : #{url}")
17
+ end
18
+
19
+ true
20
+ end
21
+
22
+ def _manage_projects
23
+ command, project, *args = *params[:arguments]
24
+ case command
25
+ when "add"
26
+ url = args.shift
27
+
28
+ raise "Not enough arguments" unless url
29
+
30
+ prompt.say "adding project: #{project}"
31
+ projects = self.class.projects
32
+ write_file("projects.json") do |f|
33
+ f << projects.merge(project => url).to_json
34
+ end
35
+ when "rm"
36
+ projects = self.class.projects
37
+
38
+ unless projects.keys.include?(project)
39
+ prompt.say("No such project: #{project}")
40
+ return
41
+ end
42
+
43
+ prompt.say "removing project: #{project}"
44
+
45
+ projects.delete(project)
46
+
47
+ write_file("projects.json") do |f|
48
+ f << projects.to_json
49
+ end
50
+ when "select"
51
+ projects = self.class.projects
52
+
53
+ unless projects.keys.include?(project)
54
+ prompt.say("No such project: #{project}")
55
+ return
56
+ end
57
+
58
+ prompt.say "selecting project: #{project}"
59
+
60
+ self.class.current_project = project
61
+ else
62
+ prompt.say "Unknown command: project #{command}"
63
+ end
64
+ end
65
+
66
+ end
@@ -0,0 +1,11 @@
1
+ Turbine::Application.extension do
2
+ def push
3
+ log_data = load_log_data
4
+
5
+ log_data.each do |record|
6
+ service["/time_entries"].post("time_entry" => record)
7
+ end
8
+
9
+ clear_log_data
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ Turbine::Application.extension do
2
+ def reset
3
+ delete_file("queue")
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ Turbine::Application.extension do
2
+ def rewind
3
+ delete_file("timestamp")
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ Turbine::Application.extension do
2
+ def staged
3
+ log_data = load_log_data
4
+
5
+ prompt.say "These entries will be created upon push:\n\n"
6
+
7
+ log_data.each_with_index do |record, i|
8
+ prompt.say " [#{i}] #{record["description"]} (#{record["hours"]} hrs)"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ Turbine::Application.extension do
2
+ def start
3
+ timer = Turbine::Timer.new
4
+ if timer.running?
5
+ prompt.say "Timer already started, please stop or rewind first"
6
+ else
7
+ timer.write_timestamp
8
+ prompt.say "Timer started at #{Time.now}"
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ Turbine::Application.extension do
2
+ def status
3
+ queue = Turbine::Queue.new
4
+
5
+ if queue.empty?
6
+ prompt.say "No entries for this commit yet\n\n"
7
+ else
8
+ entries = queue.entries.join(", ")
9
+ sum = queue.entries.inject {|sum, n| sum + n }
10
+ prompt.say "Entries for this commit: ( #{entries} )"
11
+ prompt.say "Total for this commit: #{sum}\n\n"
12
+ end
13
+
14
+ timer = Turbine::Timer.new
15
+ if timer.running?
16
+ prompt.say("Current timer started at #{timer.timestamp}")
17
+ prompt.say("Elapsed time: #{'%0.2f' % timer.elapsed_time} hrs")
18
+ else
19
+ prompt.say("Timer is not presently running")
20
+ end
21
+
22
+ prompt.say("\n")
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ Turbine::Application.extension do
2
+ def stop
3
+ timer = Turbine::Timer.new
4
+ if timer.running?
5
+ begin
6
+ duration = prompt.ask("Time to enter (CTRL-C to cancel): ", Float) do |q|
7
+ q.default = ("%0.2f" % timer.elapsed_time).to_f
8
+ end
9
+
10
+ queue = Turbine::Queue.new
11
+ queue << duration
12
+
13
+ timer.clear_timestamp
14
+ rescue Interrupt
15
+ prompt.say("\n")
16
+ end
17
+ else
18
+ prompt.say "ERROR: Timer was not running."
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,40 @@
1
+ module Turbine
2
+ class Queue
3
+ include Enumerable
4
+
5
+ def initialize(dir=Turbine::Application.config_dir)
6
+ @file = "#{dir}/queue"
7
+ end
8
+
9
+ def <<(duration)
10
+ File.open(@file, "a") { |f| f.puts(duration.to_s)}
11
+ self
12
+ end
13
+
14
+ def empty?
15
+ !File.exist?(@file)
16
+ end
17
+
18
+ def entries
19
+ return [] if empty?
20
+
21
+ File.read(@file).split("\n").map { |e| e.to_f }
22
+ end
23
+
24
+ def each
25
+ entries.each { |e| yield(e) }
26
+ end
27
+
28
+ def sum
29
+ return 0 if empty?
30
+
31
+ File.foreach(@file).inject(0) do |sum, line|
32
+ sum + line.to_f
33
+ end
34
+ end
35
+
36
+ def clear
37
+ FileUtils.rm_f(@file)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require "fileutils"
2
+ require "time"
3
+ require "date"
4
+
5
+ module Turbine
6
+ class Timer
7
+ MissingTimestampError = Class.new(StandardError)
8
+
9
+ def initialize(dir=Turbine::Application.config_dir)
10
+ @file = "#{dir}/timestamp"
11
+ end
12
+
13
+ def write_timestamp
14
+ File.open(@file, "w") { |f| f << Time.now.utc.to_s }
15
+ end
16
+
17
+ def timestamp
18
+ raise MissingTimestampError unless running?
19
+ Time.parse(File.read(@file)).localtime
20
+ end
21
+
22
+ def elapsed_time
23
+ (Time.now.utc - timestamp.utc) / 60.0 / 60.0
24
+ end
25
+
26
+ def clear_timestamp
27
+ FileUtils.rm_f(@file)
28
+ end
29
+
30
+ def running?
31
+ File.exist?(@file)
32
+ end
33
+ end
34
+ end
35
+
metadata ADDED
@@ -0,0 +1,86 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mm
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Gregory Brown
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-10 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: " Seeekrit\n"
23
+ email: " gregory.t.brown@gmail.com"
24
+ executables:
25
+ - mm
26
+ extensions: []
27
+
28
+ extra_rdoc_files: []
29
+
30
+ files:
31
+ - lib/turbine/application.rb
32
+ - lib/turbine/command_runner.rb
33
+ - lib/turbine/timer.rb
34
+ - lib/turbine/queue.rb
35
+ - lib/turbine/commands/standard/staged.rb
36
+ - lib/turbine/commands/standard/start.rb
37
+ - lib/turbine/commands/standard/add.rb
38
+ - lib/turbine/commands/standard/reset.rb
39
+ - lib/turbine/commands/standard/drop.rb
40
+ - lib/turbine/commands/standard/status.rb
41
+ - lib/turbine/commands/standard/push.rb
42
+ - lib/turbine/commands/standard/rewind.rb
43
+ - lib/turbine/commands/standard/project.rb
44
+ - lib/turbine/commands/standard/commit.rb
45
+ - lib/turbine/commands/standard/stop.rb
46
+ - lib/turbine/commands/init.rb
47
+ - lib/turbine.rb
48
+ - data/config.rb.erb
49
+ - bin/mm
50
+ - Rakefile
51
+ has_rdoc: true
52
+ homepage: http://pixelpowerhouse.com
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options: []
57
+
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ hash: 3
66
+ segments:
67
+ - 0
68
+ version: "0"
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 3
75
+ segments:
76
+ - 0
77
+ version: "0"
78
+ requirements: []
79
+
80
+ rubyforge_project:
81
+ rubygems_version: 1.3.7
82
+ signing_key:
83
+ specification_version: 3
84
+ summary: A seecret
85
+ test_files: []
86
+