one_inch_punch 0.4.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,11 @@
1
+ == 0.5.0 2010-11-18
2
+
3
+ * 1 minor enhancement:
4
+ * added 'age' command
5
+ * moves project data to an old-version name, e.g. project -> project_old/1
6
+ * cascades old-version project data, e.g. project -> project_old/1, project_old/1 -> project_old/2
7
+ * can take a :before option to only move a subset of data
8
+
1
9
  == 0.4.2 2010-08-16
2
10
 
3
11
  * 1 tiny enhancement:
@@ -6,13 +14,13 @@
6
14
  * option can be given on command-line with --on
7
15
  * :before and :after can also take dates now, converting them to times
8
16
 
9
- == 0.4.1 2008-08-26
17
+ == 0.4.1 2009-08-26
10
18
 
11
19
  * 1 tiny enhancement:
12
20
  * allowing command-line log message to be specified with --message
13
21
  (will take precedence over normal message argument if both are specified)
14
22
 
15
- == 0.4.0 2008-08-17
23
+ == 0.4.0 2009-08-17
16
24
 
17
25
  * 1 minor enhancement:
18
26
  * added 'summary' command
@@ -23,24 +31,24 @@
23
31
  * 1 tiny bugfix
24
32
  * full status now works with "short" (only display what's punched-in) instead of always showing 'out'
25
33
 
26
- == 0.3.3 2008-06-25
34
+ == 0.3.3 2009-06-25
27
35
 
28
36
  * 1 tiny enhancement:
29
37
  * added 'short' status, which only displays what's currently punched in (or 'out' if nothing)
30
38
  * punch command displays status as YAML if it's a hash, like it does for total
31
39
 
32
- == 0.3.2 2008-06-01
40
+ == 0.3.2 2009-06-01
33
41
 
34
42
  * 1 tiny bugfix enhancement:
35
43
  * sub-projects now truly restricting to the naming form of 'parent/child',
36
44
  not 'parent_child' or even simply 'parentseriouslythisisnotachild'
37
45
 
38
- == 0.3.1 2008-04-06
46
+ == 0.3.1 2009-04-06
39
47
 
40
48
  * 1 tiny bugfix enhancement:
41
49
  * Total no longer erroring on non-existent parent project
42
50
 
43
- == 0.3.0 2008-04-05
51
+ == 0.3.0 2009-04-05
44
52
 
45
53
  * 1 minor enhancement:
46
54
  * Can now have 'sub-projects', or projects with names of the form 'parent/child'
data/bin/punch CHANGED
@@ -126,6 +126,14 @@ commands = {
126
126
  else
127
127
  puts "Project required"
128
128
  end
129
+ end,
130
+ 'age' => lambda do |project|
131
+ if project
132
+ Punch.write if result = Punch.age(project, OPTIONS)
133
+ puts result.inspect
134
+ else
135
+ puts "Project required"
136
+ end
129
137
  end
130
138
  }
131
139
 
data/lib/punch.rb CHANGED
@@ -158,21 +158,22 @@ class Punch
158
158
  summary = Hash.new(0)
159
159
 
160
160
  list_data.each do |time_data|
161
- unless (time_data['log'] || []).empty?
162
- log = time_data['log'].collect do |l|
163
- msg, time = l.split('@')
164
- msg = msg.strip
165
- msg = 'unspecified' if msg == 'punch in'
166
- { :msg => msg, :time => Time.parse(time) }
167
- end
168
-
169
- log << { :msg => 'punch out', :time => Time.now } unless log.last[:msg] == 'punch out'
170
-
171
- log.each_cons(2) do |a, b|
172
- summary[a[:msg]] += (b[:time] - a[:time]).to_i
173
- end
174
- else
161
+ if (time_data['log'] || []).empty?
175
162
  summary['unspecified'] += ((time_data['out'] || Time.now) - time_data['in']).to_i
163
+ next
164
+ end
165
+
166
+ log = time_data['log'].collect do |l|
167
+ msg, time = l.split('@')
168
+ msg = msg.strip
169
+ msg = 'unspecified' if msg == 'punch in'
170
+ { :msg => msg, :time => Time.parse(time) }
171
+ end
172
+
173
+ log << { :msg => 'punch out', :time => Time.now } unless log.last[:msg] == 'punch out'
174
+
175
+ log.each_cons(2) do |a, b|
176
+ summary[a[:msg]] += (b[:time] - a[:time]).to_i
176
177
  end
177
178
  end
178
179
 
@@ -181,6 +182,27 @@ class Punch
181
182
  summary
182
183
  end
183
184
 
185
+ def age(project, options = {})
186
+ raise ":after option makes no sense for aging" if options[:after]
187
+ return nil unless projects.include?(project)
188
+
189
+ if project.match(%r{_old/\d+$})
190
+ aged_project = project.succ
191
+ else
192
+ aged_project = "#{project}_old/1"
193
+ end
194
+
195
+ age(aged_project)
196
+ if options[:before]
197
+ data[aged_project], data[project] = data[project].partition { |d| d['out'] < options[:before] }
198
+ [project, aged_project].each { |proj| data.delete(proj) if data[proj].empty? }
199
+ else
200
+ data[aged_project] = data.delete(project)
201
+ end
202
+
203
+ true
204
+ end
205
+
184
206
 
185
207
  private
186
208
 
@@ -41,6 +41,10 @@ class Punch
41
41
  self.class.summary(project, options)
42
42
  end
43
43
 
44
+ def age(options = {})
45
+ self.class.age(project, options)
46
+ end
47
+
44
48
  def ==(other)
45
49
  project == other.project
46
50
  end
data/lib/punch/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  class Punch
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
- MINOR = 4
5
- TINY = 2
4
+ MINOR = 5
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -853,6 +853,90 @@ describe 'punch command' do
853
853
  end
854
854
  end
855
855
 
856
+ describe "when the command is 'age'" do
857
+ before do
858
+ Punch.stub!(:age)
859
+ end
860
+
861
+ it 'should load punch data' do
862
+ Punch.should.receive(:load)
863
+ run_command('age', @project)
864
+ end
865
+
866
+ it 'should age the given project' do
867
+ Punch.stub!(:write)
868
+ Punch.should.receive(:age) do |proj, _|
869
+ proj.should == @project
870
+ end
871
+ run_command('age', @project)
872
+ end
873
+
874
+ describe 'when options specified' do
875
+ it "should pass on a 'before' time option given by --before" do
876
+ time_option = '2008-08-23 15:39'
877
+ time = Time.local(2008, 8, 23, 15, 39)
878
+ Punch.should.receive(:age) do |proj, options|
879
+ proj.should == @project
880
+ options[:before].should == time
881
+ end
882
+ run_command('age', @project, '--before', time_option)
883
+ end
884
+
885
+ it 'should handle a time option given as a date' do
886
+ time_option = '2008-08-23'
887
+ time = Time.local(2008, 8, 23)
888
+ Punch.should.receive(:age) do |proj, options|
889
+ proj.should == @project
890
+ options[:before].should == time
891
+ end
892
+ run_command('age', @project, '--before', time_option)
893
+ end
894
+ end
895
+
896
+ it 'should output the result' do
897
+ result = 'result'
898
+ Punch.stub!(:age).and_return(result)
899
+ self.should.receive(:puts).with(result.inspect)
900
+ run_command('age', @project)
901
+ end
902
+
903
+ describe 'when aged successfully' do
904
+ it 'should write the data' do
905
+ Punch.stub!(:age).and_return(true)
906
+ Punch.should.receive(:write)
907
+ run_command('age', @project)
908
+ end
909
+ end
910
+
911
+ describe 'when not aged successfully' do
912
+ it 'should not write the data' do
913
+ Punch.stub!(:age).and_return(nil)
914
+ Punch.should.receive(:write).never
915
+ run_command('age', @project)
916
+ end
917
+ end
918
+
919
+ describe 'when no project given' do
920
+ it 'should display an error message' do
921
+ self.should.receive(:puts) do |output|
922
+ output.should.match(/project.+require/i)
923
+ end
924
+ run_command('age')
925
+ end
926
+
927
+ it 'should not age' do
928
+ Punch.stub!(:write)
929
+ Punch.should.receive(:age).never
930
+ run_command('age')
931
+ end
932
+
933
+ it 'should not write the data' do
934
+ Punch.should.receive(:write).never
935
+ run_command('age')
936
+ end
937
+ end
938
+ end
939
+
856
940
  describe 'when the command is unknown' do
857
941
  it 'should not error' do
858
942
  lambda { run_command('bunk') }.should.not.raise
@@ -871,7 +955,7 @@ describe 'punch command' do
871
955
  end
872
956
 
873
957
  it 'should not run any punch command' do
874
- [:in, :out, :delete, :status, :total, :log, :list, :summary].each do |command|
958
+ [:in, :out, :delete, :status, :total, :log, :list, :summary, :age].each do |command|
875
959
  Punch.should.receive(command).never
876
960
  end
877
961
  run_command('bunk')
@@ -432,6 +432,56 @@ describe Punch, 'instance' do
432
432
  end
433
433
  end
434
434
 
435
+ it 'should age the project' do
436
+ @punch.should.respond_to(:age)
437
+ end
438
+
439
+ describe 'aging project' do
440
+ before do
441
+ @age = 'age val'
442
+ Punch.stub!(:age).and_return(@age)
443
+ end
444
+
445
+ it 'should accept options' do
446
+ lambda { @punch.age(:before => Time.now) }.should.not.raise(ArgumentError)
447
+ end
448
+
449
+ it 'should not require options' do
450
+ lambda { @punch.age }.should.not.raise(ArgumentError)
451
+ end
452
+
453
+ it 'should delegate to the class' do
454
+ Punch.should.receive(:age)
455
+ @punch.age
456
+ end
457
+
458
+ it 'should pass the project when delegating to the class' do
459
+ Punch.should.receive(:age) do |proj, _|
460
+ proj.should == @project
461
+ end
462
+ @punch.age
463
+ end
464
+
465
+ it 'should pass the options when delegating to the class' do
466
+ options = { :before => Time.now }
467
+ Punch.should.receive(:age) do |_, opts|
468
+ opts.should == options
469
+ end
470
+ @punch.age(options)
471
+ end
472
+
473
+ it 'should pass an empty hash if no options given' do
474
+ Punch.should.receive(:age) do |_, opts|
475
+ opts.should == {}
476
+ end
477
+ @punch.age
478
+ end
479
+
480
+ it 'should return the value returned by the class method' do
481
+ @punch.age.should == @age
482
+ end
483
+ end
484
+
435
485
  describe 'equality' do
436
486
  it 'should be equal to another instance for the same project' do
437
487
  Punch.new('proj').should == Punch.new('proj')
data/spec/punch_spec.rb CHANGED
@@ -1576,10 +1576,6 @@ describe Punch do
1576
1576
  end
1577
1577
 
1578
1578
  describe 'providing a summary of project time use' do
1579
- def format_time(time)
1580
- time.strftime()
1581
- end
1582
-
1583
1579
  before do
1584
1580
  @message = 'test usage'
1585
1581
  @now = Time.now
@@ -1766,4 +1762,105 @@ describe Punch do
1766
1762
  end
1767
1763
  end
1768
1764
  end
1765
+
1766
+ it 'should age a project' do
1767
+ Punch.should.respond_to(:age)
1768
+ end
1769
+
1770
+ describe 'aging a project' do
1771
+ before do
1772
+ @now = Time.now
1773
+ Time.stub!(:now).and_return(@now)
1774
+ @project = 'pro-ject'
1775
+ @data = { @project => [ {'in' => @now - 3000} ] }
1776
+
1777
+ Punch.instance_eval do
1778
+ class << self
1779
+ public :data, :data=
1780
+ end
1781
+ end
1782
+ Punch.data = @data
1783
+ end
1784
+
1785
+ it 'should accept a project name' do
1786
+ lambda { Punch.age('proj') }.should.not.raise(ArgumentError)
1787
+ end
1788
+
1789
+ it 'should require a project name' do
1790
+ lambda { Punch.age }.should.raise(ArgumentError)
1791
+ end
1792
+
1793
+ it 'should accept options' do
1794
+ lambda { Punch.age('proj', :before => @now - 5000) }.should.not.raise(ArgumentError)
1795
+ end
1796
+
1797
+ describe 'when the project exists' do
1798
+ it 'should move the project to #{project}_old/1' do
1799
+ Punch.age(@project)
1800
+ Punch.data.should == { "#{@project}_old/1" => [ {'in' => @now - 3000} ] }
1801
+ end
1802
+
1803
+ it 'should simply increment the number of a project name in the x_old/1 format' do
1804
+ @data = { 'some_old/1' => [ {'in' => @now - 3900} ] }
1805
+ Punch.data = @data
1806
+
1807
+ Punch.age('some_old/1')
1808
+ Punch.data.should == { "some_old/2" => [ {'in' => @now - 3900} ] }
1809
+ end
1810
+
1811
+ it 'should cascade aging a project to older versions' do
1812
+ @data["#{@project}_old/1"] = [ {'in' => @now - 50000, 'out' => @now - 40000} ]
1813
+ @data["#{@project}_old/2"] = [ {'in' => @now - 90000, 'out' => @now - 85000} ]
1814
+ Punch.data = @data
1815
+
1816
+ Punch.age(@project)
1817
+ Punch.data.should == { "#{@project}_old/1" => [ {'in' => @now - 3000} ], "#{@project}_old/2" => [ {'in' => @now - 50000, 'out' => @now - 40000} ], "#{@project}_old/3" => [ {'in' => @now - 90000, 'out' => @now - 85000} ] }
1818
+ end
1819
+
1820
+ it 'should return true' do
1821
+ Punch.age(@project).should == true
1822
+ end
1823
+
1824
+ describe 'when options given' do
1825
+ before do
1826
+ @data = { @project => [ {'in' => @now - 5000, 'out' => @now - 4000}, {'in' => @now - 3500, 'out' => @now - 3000}, {'in' => @now - 1500, 'out' => @now - 900}, {'in' => @now - 500, 'out' => @now - 400} ] }
1827
+ Punch.data = @data
1828
+ end
1829
+
1830
+ it 'should only move the appropriate data to the old-version project' do
1831
+ expected = { @project => [ {'in' => @now - 1500, 'out' => @now - 900}, {'in' => @now - 500, 'out' => @now - 400} ],
1832
+ "#{@project}_old/1" => [ {'in' => @now - 5000, 'out' => @now - 4000}, {'in' => @now - 3500, 'out' => @now - 3000} ]
1833
+ }
1834
+ Punch.age(@project, :before => @now - 1500)
1835
+ Punch.data.should == expected
1836
+ end
1837
+
1838
+ it 'should not create an old project if no data would be moved' do
1839
+ expected = { @project => [ {'in' => @now - 5000, 'out' => @now - 4000}, {'in' => @now - 3500, 'out' => @now - 3000}, {'in' => @now - 1500, 'out' => @now - 900}, {'in' => @now - 500, 'out' => @now - 400} ] }
1840
+ Punch.age(@project, :before => @now - 50000)
1841
+ Punch.data.should == expected
1842
+ end
1843
+
1844
+ it 'should remove the project if all data would be moved' do
1845
+ expected = { "#{@project}_old/1" => [ {'in' => @now - 5000, 'out' => @now - 4000}, {'in' => @now - 3500, 'out' => @now - 3000}, {'in' => @now - 1500, 'out' => @now - 900}, {'in' => @now - 500, 'out' => @now - 400} ] }
1846
+ Punch.age(@project, :before => @now - 10)
1847
+ Punch.data.should == expected
1848
+ end
1849
+
1850
+ it 'should not accept an after option' do
1851
+ lambda { Punch.age(@project, :after => @now - 500) }.should.raise
1852
+ end
1853
+ end
1854
+ end
1855
+
1856
+ describe 'when the project does not exist' do
1857
+ before do
1858
+ @project = 'no dice'
1859
+ end
1860
+
1861
+ it 'should return nil' do
1862
+ Punch.age(@project).should.be.nil
1863
+ end
1864
+ end
1865
+ end
1769
1866
  end
metadata CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
- - 4
9
- - 2
10
- version: 0.4.2
8
+ - 5
9
+ - 0
10
+ version: 0.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Yossef Mendelssohn
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-16 00:00:00 -05:00
18
+ date: 2010-11-18 00:00:00 -06:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -74,12 +74,12 @@ dependencies:
74
74
  requirements:
75
75
  - - ">="
76
76
  - !ruby/object:Gem::Version
77
- hash: 21
77
+ hash: 19
78
78
  segments:
79
79
  - 2
80
80
  - 6
81
- - 1
82
- version: 2.6.1
81
+ - 2
82
+ version: 2.6.2
83
83
  type: :development
84
84
  version_requirements: *id004
85
85
  description: a simple time-tracking tool