one_inch_punch 0.5.1 → 0.6.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,10 @@
1
+ == 0.6.0 2012-04-10
2
+
3
+ * 1 minor enhancement:
4
+ * adding 'entry' command:
5
+ * combines in+out into one command, requiring from (in) and to (out) times
6
+ * has 'clock' alias
7
+
1
8
  == 0.5.1 2012-03-19
2
9
 
3
10
  * 1 tiny bugfix:
data/bin/punch CHANGED
@@ -33,6 +33,10 @@ BANNER
33
33
  "Restrict command to only on the given date") { |date| OPTIONS[:on] = Date.parse(date) }
34
34
  opts.on('--at [TIME]', '--time [TIME]', String,
35
35
  "Use the given time") { |time| OPTIONS[:time] = Time.parse(time) }
36
+ opts.on('--from [TIME]', String,
37
+ "Use the given time") { |time| OPTIONS[:from] = Time.parse(time) }
38
+ opts.on('--to [TIME]', String,
39
+ "Use the given time") { |time| OPTIONS[:to] = Time.parse(time) }
36
40
  opts.on('-m', '--message [MESSAGE]', String,
37
41
  "Use the given log message") { |message| OPTIONS[:message] = message }
38
42
  opts.on('--full',
@@ -104,6 +108,17 @@ commands = {
104
108
  puts message
105
109
  end
106
110
  end,
111
+ 'entry' => lambda do |project|
112
+ if project
113
+ if Punch.entry(project, OPTIONS)
114
+ Punch.write
115
+ else
116
+ puts "Cannot create entry for '#{project}'"
117
+ end
118
+ else
119
+ puts "Project required"
120
+ end
121
+ end,
107
122
  'log' => lambda do |project|
108
123
  if project
109
124
  if message = OPTIONS.delete(:message) || ARGV[2]
@@ -136,6 +151,7 @@ commands = {
136
151
  end
137
152
  end
138
153
  }
154
+ commands['clock'] = commands['entry']
139
155
 
140
156
  if command_code = commands[command]
141
157
  command_code.call(project)
data/lib/punch.rb CHANGED
@@ -108,7 +108,19 @@ class Punch
108
108
  end
109
109
  true
110
110
  end
111
-
111
+
112
+ def entry(project, options = {})
113
+ raise ArgumentError, 'both :from and :to time are needed' unless options[:from] and options[:to]
114
+
115
+ in_options = { :time => options[:from] }
116
+ in_options[:message] = options[:message] if options[:message]
117
+ result = self.in(project, in_options)
118
+ return result unless result
119
+
120
+ out(project, :time => options[:to])
121
+ end
122
+ alias_method :clock, :entry
123
+
112
124
  def delete(project)
113
125
  return nil unless data.delete(project)
114
126
  true
@@ -24,7 +24,12 @@ class Punch
24
24
  def out(options = {})
25
25
  self.class.out(project, options)
26
26
  end
27
-
27
+
28
+ def entry(options = {})
29
+ self.class.entry(project, options)
30
+ end
31
+ alias_method :clock, :entry
32
+
28
33
  def list(options = {})
29
34
  self.class.list(project, options)
30
35
  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 = 5
5
- TINY = 1
4
+ MINOR = 6
5
+ TINY = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -467,7 +467,127 @@ describe 'punch command' do
467
467
  end
468
468
  end
469
469
  end
470
-
470
+
471
+ describe "when the command is 'entry'" do
472
+ before do
473
+ Punch.stub!(:entry)
474
+ @from_option = '2012-04-10 14:39'
475
+ @to_option = '2012-04-10 17:43'
476
+ end
477
+
478
+ it 'should load punch data' do
479
+ Punch.should.receive(:load)
480
+ run_command('entry', @project)
481
+ end
482
+
483
+ it 'should make a punch entry for the given project' do
484
+ from_option = '2012-04-10 14:39'
485
+ from_time = Time.local(2012, 4, 10, 14, 39)
486
+ to_option = '2012-04-10 17:43'
487
+ to_time = Time.local(2012, 4, 10, 17, 43)
488
+
489
+ Punch.should.receive(:entry) do |proj, options|
490
+ proj.should == @project
491
+ options[:from].should == from_time
492
+ options[:to ].should == to_time
493
+ end
494
+
495
+ run_command('entry', @project, '--from', from_option, '--to', to_option)
496
+ end
497
+
498
+ it 'should pass a message if specified on the command line (with --message)' do
499
+ message = 'About to do some amazing work'
500
+
501
+ Punch.should.receive(:entry) do |proj, options|
502
+ proj.should == @project
503
+ options[:message].should == message
504
+ end
505
+
506
+ run_command('entry', @project, '--from', @from_option, '--to', @to_option, '--message', message)
507
+ end
508
+
509
+ it 'should pass a message if specified on the command line (with -m)' do
510
+ message = 'About to do some amazing work'
511
+
512
+ Punch.should.receive(:entry) do |proj, options|
513
+ proj.should == @project
514
+ options[:message].should == message
515
+ end
516
+
517
+ run_command('entry', @project, '--from', @from_option, '--to', @to_option, '-m', message)
518
+ end
519
+
520
+ describe 'when entry created successfully' do
521
+ before do
522
+ Punch.stub!(:entry).and_return(true)
523
+ end
524
+
525
+ it 'should write the data' do
526
+ Punch.should.receive(:write)
527
+ run_command('entry', @project, '--from', @from_option, '--to', @to_option)
528
+ end
529
+
530
+ it 'should not print anything' do
531
+ self.should.receive(:puts).never
532
+ run_command('entry', @project, '--from', @from_option, '--to', @to_option)
533
+ end
534
+ end
535
+
536
+ describe 'when entry not created successfully' do
537
+ before do
538
+ Punch.stub!(:entry).and_return(false)
539
+ end
540
+
541
+ it 'should not write the data' do
542
+ Punch.should.receive(:write).never
543
+ run_command('entry', @project, '--from', @from_option, '--to', @to_option)
544
+ end
545
+
546
+ it 'should print a message' do
547
+ self.should.receive(:puts) do |output|
548
+ output.should.match(/cannot.+entry/i)
549
+ end
550
+ run_command('entry', @project, '--from', @from_option, '--to', @to_option)
551
+ end
552
+ end
553
+
554
+ describe 'when no project given' do
555
+ it 'should display an error message' do
556
+ self.should.receive(:puts) do |output|
557
+ output.should.match(/project.+require/i)
558
+ end
559
+ run_command('entry')
560
+ end
561
+
562
+ it 'should not create an entry' do
563
+ Punch.stub!(:write)
564
+ Punch.should.receive(:entry).never
565
+ run_command('entry')
566
+ end
567
+
568
+ it 'should not write the data' do
569
+ Punch.should.receive(:write).never
570
+ run_command('entry')
571
+ end
572
+ end
573
+
574
+ it "should have 'clock' as an alias" do
575
+ from_option = '2012-04-10 14:39'
576
+ from_time = Time.local(2012, 4, 10, 14, 39)
577
+ to_option = '2012-04-10 17:43'
578
+ to_time = Time.local(2012, 4, 10, 17, 43)
579
+
580
+ Punch.should.receive(:entry) do |proj, options|
581
+ proj.should == @project
582
+ options[:from].should == from_time
583
+ options[:to ].should == to_time
584
+ end
585
+
586
+ run_command('clock', @project, '--from', from_option, '--to', to_option)
587
+ end
588
+
589
+ end
590
+
471
591
  describe "when the command is 'delete'" do
472
592
  before do
473
593
  Punch.stub!(:delete)
@@ -220,6 +220,60 @@ describe Punch, 'instance' do
220
220
  end
221
221
  end
222
222
 
223
+ it 'should make a punch entry' do
224
+ @punch.should.respond_to(:entry)
225
+ end
226
+
227
+ describe 'making a punch entry' do
228
+ before do
229
+ @entry = 'entry val'
230
+ Punch.stub!(:entry).and_return(@entry)
231
+ end
232
+
233
+ it 'should accept options' do
234
+ lambda { @punch.entry(:time => Time.now) }.should.not.raise(ArgumentError)
235
+ end
236
+
237
+ it 'should not require options' do
238
+ lambda { @punch.entry }.should.not.raise(ArgumentError)
239
+ end
240
+
241
+ it 'should delegate to the class' do
242
+ Punch.should.receive(:entry)
243
+ @punch.entry
244
+ end
245
+
246
+ it 'should pass the project when delegating to the class' do
247
+ Punch.should.receive(:entry) do |proj, _|
248
+ proj.should == @project
249
+ end
250
+ @punch.entry
251
+ end
252
+
253
+ it 'should pass the options when delegating to the class' do
254
+ options = { :time => Time.now }
255
+ Punch.should.receive(:entry) do |_, opts|
256
+ opts.should == options
257
+ end
258
+ @punch.entry(options)
259
+ end
260
+
261
+ it 'should pass an empty hash if no options given' do
262
+ Punch.should.receive(:entry) do |_, opts|
263
+ opts.should == {}
264
+ end
265
+ @punch.entry
266
+ end
267
+
268
+ it 'should return the value returned by the class method' do
269
+ @punch.entry.should == @entry
270
+ end
271
+
272
+ it 'should have clock as an alias' do
273
+ @punch.clock.should == @entry
274
+ end
275
+ end
276
+
223
277
  it 'should list the project data' do
224
278
  @punch.should.respond_to(:list)
225
279
  end
data/spec/punch_spec.rb CHANGED
@@ -990,6 +990,84 @@ describe Punch do
990
990
  end
991
991
  end
992
992
 
993
+ it 'should create a full punch entry' do
994
+ Punch.should.respond_to(:entry)
995
+ end
996
+
997
+ describe 'creating a full punch entry' do
998
+ before do
999
+ Punch.stub!(:in)
1000
+ Punch.stub!(:out)
1001
+
1002
+ @now = Time.now
1003
+ @from_time = @now - 1000
1004
+ @to_time = @now - 100
1005
+ @project = 'myproj'
1006
+ end
1007
+
1008
+ it 'should require a project name' do
1009
+ lambda { Punch.entry }.should.raise(ArgumentError)
1010
+ end
1011
+
1012
+ it 'should accept a project name and options' do
1013
+ lambda { Punch.entry('proj', :from => Time.now - 500, :to => Time.now - 20) }.should.not.raise(ArgumentError)
1014
+ end
1015
+
1016
+ it 'should require :from and :to options' do
1017
+ lambda { Punch.entry('proj') }.should.raise(ArgumentError)
1018
+ end
1019
+
1020
+ it 'should punch the project in with the given :from time' do
1021
+ Punch.should.receive(:in).with(@project, :time => @from_time)
1022
+ Punch.entry(@project, :from => @from_time, :to => @to_time)
1023
+ end
1024
+
1025
+ it 'should pass any given message when punching in' do
1026
+ msg = 'just some work'
1027
+ Punch.should.receive(:in).with(@project, :time => @from_time, :message => msg)
1028
+ Punch.entry(@project, :from => @from_time, :to => @to_time, :message => msg)
1029
+ end
1030
+
1031
+ describe 'when punching in is successful' do
1032
+ before do
1033
+ Punch.stub!(:in).and_return(true)
1034
+ end
1035
+
1036
+ it 'should punch the project out with the given :to time' do
1037
+ Punch.should.receive(:out).with(@project, :time => @to_time)
1038
+ Punch.entry(@project, :from => @from_time, :to => @to_time)
1039
+ end
1040
+
1041
+ it 'should return the result from punching out' do
1042
+ result = Object.new
1043
+ Punch.stub!(:out).and_return(result)
1044
+ Punch.entry(@project, :from => @from_time, :to => @to_time).should == result
1045
+ end
1046
+ end
1047
+
1048
+ describe 'when punching in is unsuccesful' do
1049
+ before do
1050
+ Punch.stub!(:in).and_return(false)
1051
+ end
1052
+
1053
+ it 'should not attempt the punch the project out' do
1054
+ Punch.should.receive(:out).never
1055
+ Punch.entry(@project, :from => @from_time, :to => @to_time)
1056
+ end
1057
+
1058
+ it 'should return false' do
1059
+ Punch.entry(@project, :from => @from_time, :to => @to_time).should == false
1060
+ end
1061
+ end
1062
+
1063
+ it 'should have .clock as an alias' do
1064
+ msg = 'just some work'
1065
+ Punch.should.receive(:in).with(@project, :time => @from_time, :message => msg).and_return(true)
1066
+ Punch.should.receive(:out).with(@project, :time => @to_time)
1067
+ Punch.clock(@project, :from => @from_time, :to => @to_time, :message => msg)
1068
+ end
1069
+ end
1070
+
993
1071
  it 'should delete a project' do
994
1072
  Punch.should.respond_to(:delete)
995
1073
  end
metadata CHANGED
@@ -1,57 +1,80 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: one_inch_punch
3
- version: !ruby/object:Gem::Version
4
- version: 0.5.1
3
+ version: !ruby/object:Gem::Version
4
+ hash: 7
5
5
  prerelease:
6
+ segments:
7
+ - 0
8
+ - 6
9
+ - 0
10
+ version: 0.6.0
6
11
  platform: ruby
7
- authors:
12
+ authors:
8
13
  - Yossef Mendelssohn
9
14
  autorequire:
10
15
  bindir: bin
11
16
  cert_chain: []
12
- date: 2012-03-19 00:00:00.000000000Z
13
- dependencies:
14
- - !ruby/object:Gem::Dependency
17
+
18
+ date: 2012-04-10 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
15
21
  name: bacon
16
- requirement: &2157947500 !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
17
24
  none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 19
29
+ segments:
30
+ - 1
31
+ - 1
32
+ - 0
21
33
  version: 1.1.0
22
34
  type: :development
23
- prerelease: false
24
- version_requirements: *2157947500
25
- - !ruby/object:Gem::Dependency
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
26
37
  name: facon
27
- requirement: &2157947000 !ruby/object:Gem::Requirement
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
28
40
  none: false
29
- requirements:
30
- - - ! '>='
31
- - !ruby/object:Gem::Version
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 11
45
+ segments:
46
+ - 0
47
+ - 5
48
+ - 0
32
49
  version: 0.5.0
33
50
  type: :development
34
- prerelease: false
35
- version_requirements: *2157947000
36
- - !ruby/object:Gem::Dependency
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
37
53
  name: timely
38
- requirement: &2157946540 !ruby/object:Gem::Requirement
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
39
56
  none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 29
61
+ segments:
62
+ - 0
63
+ - 0
64
+ - 1
43
65
  version: 0.0.1
44
66
  type: :runtime
45
- prerelease: false
46
- version_requirements: *2157946540
67
+ version_requirements: *id003
47
68
  description: A simple time-tracking tool, compatible with Ara T. Howard's punch gem.
48
- email:
69
+ email:
49
70
  - ymendel@pobox.com
50
- executables:
71
+ executables:
51
72
  - punch
52
73
  extensions: []
74
+
53
75
  extra_rdoc_files: []
54
- files:
76
+
77
+ files:
55
78
  - License.txt
56
79
  - History.txt
57
80
  - README.txt
@@ -68,26 +91,36 @@ files:
68
91
  - bin/punch
69
92
  homepage: http://github.com/ymendel/one_inch_punch/
70
93
  licenses: []
94
+
71
95
  post_install_message:
72
96
  rdoc_options: []
73
- require_paths:
97
+
98
+ require_paths:
74
99
  - lib
75
- required_ruby_version: !ruby/object:Gem::Requirement
100
+ required_ruby_version: !ruby/object:Gem::Requirement
76
101
  none: false
77
- requirements:
78
- - - ! '>='
79
- - !ruby/object:Gem::Version
80
- version: '0'
81
- required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
110
  none: false
83
- requirements:
84
- - - ! '>='
85
- - !ruby/object:Gem::Version
86
- version: '0'
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ hash: 3
115
+ segments:
116
+ - 0
117
+ version: "0"
87
118
  requirements: []
119
+
88
120
  rubyforge_project:
89
121
  rubygems_version: 1.8.10
90
122
  signing_key:
91
123
  specification_version: 3
92
124
  summary: Track your time locally.
93
125
  test_files: []
126
+