one_inch_punch 0.4.2 → 0.5.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.
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