tempo-cli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +56 -0
  4. data/README.md +326 -0
  5. data/Rakefile +65 -0
  6. data/bin/tempo +477 -0
  7. data/features/arrange.feature +43 -0
  8. data/features/checkout.feature +63 -0
  9. data/features/end.feature +65 -0
  10. data/features/project.feature +246 -0
  11. data/features/report.feature +62 -0
  12. data/features/start.feature +87 -0
  13. data/features/step_definitions/tempo_steps.rb +138 -0
  14. data/features/support/env.rb +26 -0
  15. data/features/tempo.feature +13 -0
  16. data/features/update.feature +69 -0
  17. data/lib/file_record/directory.rb +11 -0
  18. data/lib/file_record/directory_structure/tempo/README.txt +4 -0
  19. data/lib/file_record/directory_structure/tempo/tempo_projects.yaml +6 -0
  20. data/lib/file_record/record.rb +120 -0
  21. data/lib/tempo/controllers/arrange_controller.rb +52 -0
  22. data/lib/tempo/controllers/base.rb +117 -0
  23. data/lib/tempo/controllers/checkout_controller.rb +42 -0
  24. data/lib/tempo/controllers/end_controller.rb +42 -0
  25. data/lib/tempo/controllers/projects_controller.rb +107 -0
  26. data/lib/tempo/controllers/records_controller.rb +21 -0
  27. data/lib/tempo/controllers/report_controller.rb +55 -0
  28. data/lib/tempo/controllers/start_controller.rb +42 -0
  29. data/lib/tempo/controllers/update_controller.rb +78 -0
  30. data/lib/tempo/models/base.rb +176 -0
  31. data/lib/tempo/models/composite.rb +71 -0
  32. data/lib/tempo/models/log.rb +194 -0
  33. data/lib/tempo/models/project.rb +73 -0
  34. data/lib/tempo/models/time_record.rb +235 -0
  35. data/lib/tempo/version.rb +3 -0
  36. data/lib/tempo/views/arrange_view.rb +27 -0
  37. data/lib/tempo/views/base.rb +82 -0
  38. data/lib/tempo/views/formatters/base.rb +30 -0
  39. data/lib/tempo/views/formatters/screen.rb +86 -0
  40. data/lib/tempo/views/projects_view.rb +82 -0
  41. data/lib/tempo/views/report_view.rb +26 -0
  42. data/lib/tempo/views/reporter.rb +70 -0
  43. data/lib/tempo/views/time_record_view.rb +30 -0
  44. data/lib/tempo/views/view_records/base.rb +117 -0
  45. data/lib/tempo/views/view_records/composite.rb +40 -0
  46. data/lib/tempo/views/view_records/log.rb +28 -0
  47. data/lib/tempo/views/view_records/project.rb +32 -0
  48. data/lib/tempo/views/view_records/time_record.rb +48 -0
  49. data/lib/tempo.rb +26 -0
  50. data/lib/time_utilities.rb +30 -0
  51. data/tempo-cli.gemspec +26 -0
  52. data/test/lib/file_record/directory_test.rb +30 -0
  53. data/test/lib/file_record/record_test.rb +106 -0
  54. data/test/lib/tempo/controllers/base_controller_test.rb +60 -0
  55. data/test/lib/tempo/controllers/project_controller_test.rb +24 -0
  56. data/test/lib/tempo/models/base_test.rb +173 -0
  57. data/test/lib/tempo/models/composite_test.rb +76 -0
  58. data/test/lib/tempo/models/log_test.rb +171 -0
  59. data/test/lib/tempo/models/project_test.rb +105 -0
  60. data/test/lib/tempo/models/time_record_test.rb +212 -0
  61. data/test/lib/tempo/views/base_test.rb +31 -0
  62. data/test/lib/tempo/views/formatters/base_test.rb +13 -0
  63. data/test/lib/tempo/views/formatters/screen_test.rb +94 -0
  64. data/test/lib/tempo/views/reporter_test.rb +40 -0
  65. data/test/lib/tempo/views/view_records/base_test.rb +77 -0
  66. data/test/lib/tempo/views/view_records/composite_test.rb +57 -0
  67. data/test/lib/tempo/views/view_records/log_test.rb +28 -0
  68. data/test/lib/tempo/views/view_records/project_test.rb +0 -0
  69. data/test/lib/tempo/views/view_records/time_record_test.rb +0 -0
  70. data/test/support/factories.rb +177 -0
  71. data/test/support/helpers.rb +69 -0
  72. data/test/test_helper.rb +31 -0
  73. metadata +230 -0
@@ -0,0 +1,173 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+
5
+ before do
6
+ # See Rakefile for directory prep and cleanup
7
+ @dir = File.join( Dir.home,"tempo" )
8
+ Dir.mkdir(@dir, 0700) unless File.exists?(@dir)
9
+ end
10
+
11
+ describe "Model::Base" do
12
+
13
+ it "inheritale from" do
14
+ Tempo::Model::Animal.superclass.must_equal Tempo::Model::Base
15
+ end
16
+
17
+ it "grants child objects the freeze-dry method" do
18
+ frog_factory
19
+ frozen = @gray_tree_frog.freeze_dry
20
+ frozen.must_equal( {:id=>1, :genious=>"hyla", :species=>"h. versicolor"} )
21
+ end
22
+
23
+ it "grants child objects a self indexing method" do
24
+ frog_factory
25
+ Tempo::Model::Animal.index.length.must_equal 5
26
+ Tempo::Model::Animal.index.each do |animal|
27
+ animal.id.must_be_kind_of(Integer)
28
+ animal.genious.must_match "hyla"
29
+ animal.species.must_match /^h\. \w./
30
+ end
31
+ end
32
+
33
+ it "creates a file name to save to" do
34
+ frog_factory
35
+ Tempo::Model::Animal.file.must_equal "tempo_animals.yaml"
36
+ end
37
+
38
+ it "grants children the ability to write to a file" do
39
+ frog_factory
40
+ test_file = File.join(ENV['HOME'],'tempo','tempo_animals.yaml')
41
+ File.delete(test_file) if File.exists?( test_file )
42
+ contents = Tempo::Model::Animal.save_to_file
43
+ contents = eval_file_as_array( test_file )
44
+ contents.must_equal ["---", ":id: 1", ":genious: hyla", ":species: h. versicolor",
45
+ "---", ":id: 2", ":genious: hyla", ":species: h. chrysoscelis",
46
+ "---", ":id: 3", ":genious: hyla", ":species: h. avivoca",
47
+ "---", ":id: 4", ":genious: hyla", ":species: h. andersonii",
48
+ "---", ":id: 5", ":genious: hyla", ":species: h. chinensis" ]
49
+ end
50
+
51
+ it "grants children ability to read from a file" do
52
+ test_file = File.join(ENV['HOME'],'tempo','tempo_animals.yaml')
53
+ File.delete(test_file) if File.exists?( test_file )
54
+ file_lines = [ "---", ":id: 11", ":genious: hyla", ":species: h. versicolor",
55
+ "---", ":id: 12", ":genious: hyla", ":species: h. chrysoscelis",
56
+ "---", ":id: 14", ":genious: hyla", ":species: h. andersonii",
57
+ "---", ":id: 13", ":genious: hyla", ":species: h. avivoca",
58
+ "---", ":id: 15", ":genious: hyla", ":species: h. chinensis" ]
59
+ File.open( test_file,'a' ) do |f|
60
+ file_lines.each do |l|
61
+ f.puts l
62
+ end
63
+ end
64
+ Tempo::Model::Animal.clear_all
65
+ Tempo::Model::Animal.read_from_file
66
+ Tempo::Model::Animal.ids.must_equal [11,12,13,14,15]
67
+ Tempo::Model::Animal.index.each do |animal|
68
+ animal.id.must_be_kind_of(Integer)
69
+ animal.genious.must_match "hyla"
70
+ animal.species.must_match /^h\. \w./
71
+ end
72
+ end
73
+
74
+ it "gives id as a readable attribute" do
75
+ frog_factory
76
+ @gray_tree_frog.id.must_equal 1
77
+ end
78
+
79
+ it "manages uniqe ids" do
80
+ frog_factory
81
+ @copes_gray_tree_frog.id.must_equal 2
82
+ end
83
+
84
+ it "handles ids assigned and out of order" do
85
+ frog_factory
86
+ Tempo::Model::Animal.ids.must_equal [1,2,3,4,5]
87
+ @pine_barrens_tree_frog.id.must_equal 4
88
+ @bird_voiced_tree_frog.id.must_equal 3
89
+ @chinese_tree_frog.id.must_equal 5
90
+ end
91
+
92
+ it "raises an error on duplicate id" do
93
+ frog_factory
94
+ args = { genious: "hyla",
95
+ species: "h. flatulus",
96
+ id: 1
97
+ }
98
+ proc { gassy_tree_frog = Tempo::Model::Animal.new( args ) }.must_raise Tempo::Model::IdentityConflictError
99
+ end
100
+
101
+ it "finds matching instances of the class" do
102
+ frog_factory
103
+ search = Tempo::Model::Animal.find("id", 2)
104
+ search.must_equal [ @copes_gray_tree_frog ]
105
+
106
+ search = Tempo::Model::Animal.find("species", "h. versicolor" )
107
+ search.must_equal [ @gray_tree_frog ]
108
+
109
+ search = Tempo::Model::Animal.find("species", /h\. / )
110
+ search.length.must_equal 5
111
+ end
112
+
113
+ it "uses case insensitivity searches" do
114
+ frog_factory
115
+ search = Tempo::Model::Animal.find("species", "Versicolor" )
116
+ search.must_equal [ @gray_tree_frog ]
117
+ end
118
+
119
+ it "has a find_by_ method" do
120
+ frog_factory
121
+ search = Tempo::Model::Animal.find_by_id(2)
122
+ search.must_equal @copes_gray_tree_frog
123
+
124
+ search = Tempo::Model::Animal.find_by_species("h. versicolor")
125
+ search.must_equal [ @gray_tree_frog ]
126
+
127
+ search = Tempo::Model::Animal.find_by_species("Versicolor")
128
+ search.must_equal [ @gray_tree_frog ]
129
+
130
+ # # test, does this work, and should it?
131
+ # search = Tempo::Model::Animal.find_by_species("h. color")
132
+ # search.must_equal [ @gray_tree_frog ]
133
+
134
+ search = Tempo::Model::Animal.find_by_genious("hyla")
135
+ search.length.must_equal 5
136
+
137
+ search = Tempo::Model::Animal.find_by_genious_and_species("hyla", /versicolor/)
138
+ search.must_equal [ @gray_tree_frog ]
139
+ end
140
+
141
+ it "has a sort_by_ method" do
142
+ frog_factory
143
+ list = Tempo::Model::Animal.sort_by_species [ @gray_tree_frog, @pine_barrens_tree_frog ]
144
+ list.must_equal [ @pine_barrens_tree_frog, @gray_tree_frog ]
145
+
146
+ list = Tempo::Model::Animal.sort_by_id [ @gray_tree_frog, @pine_barrens_tree_frog ]
147
+ list.must_equal [ @gray_tree_frog, @pine_barrens_tree_frog ]
148
+
149
+ list = Tempo::Model::Animal.sort_by_species
150
+ list.must_equal [ @pine_barrens_tree_frog, @bird_voiced_tree_frog,
151
+ @chinese_tree_frog, @copes_gray_tree_frog, @gray_tree_frog ]
152
+
153
+ list = Tempo::Model::Animal.sort_by_species do |frog|
154
+ species_list = ""
155
+ frog.each do |f|
156
+ species_list += "#{f.species}, "
157
+ end
158
+ species_list[0..-3]
159
+ end
160
+ list.must_equal "h. andersonii, h. avivoca, h. chinensis, h. chrysoscelis, h. versicolor"
161
+ end
162
+
163
+ it "has a method_missing method" do
164
+ proc { Tempo::Model::Animal.foo }.must_raise NoMethodError
165
+ end
166
+
167
+ it "has a delete instance method" do
168
+ frog_factory
169
+ @gray_tree_frog.delete
170
+ Tempo::Model::Animal.ids.must_equal [2,3,4,5]
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,76 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+
5
+ before do
6
+ # See Rakefile for directory prep and cleanup
7
+ @dir = File.join( Dir.home,"tempo" )
8
+ Dir.mkdir(@dir, 0700) unless File.exists?(@dir)
9
+ end
10
+
11
+ describe "Model::Composite" do
12
+
13
+ it "should inherit readable only id" do
14
+ tree_factory
15
+ inherits_attr_read_only?( @forest[0], :id ).must_equal true
16
+ end
17
+
18
+ it "should find a project by id" do
19
+ tree_factory
20
+ project = Tempo::Model::Tree.find_by_id(4)
21
+ project.must_equal @forest[3]
22
+ end
23
+
24
+ it "should come with freeze dry for free" do
25
+ tree_factory
26
+ @forest[2].freeze_dry.must_equal({:id=>3, :parent=>1, :children=>[7,8], :position=>"branch1"})
27
+ end
28
+
29
+ it "should save to file a collection of composits" do
30
+ tree_factory
31
+ test_file = File.join(ENV['HOME'],'tempo','tempo_trees.yaml')
32
+ Tempo::Model::Tree.save_to_file
33
+ contents = eval_file_as_array( test_file )
34
+ contents.must_equal [ "---", ":id: 1", ":parent: :root", ":children:", "- 3", ":position: root1",
35
+ "---", ":id: 2", ":parent: :root", ":children:", "- 4", "- 5", ":position: root2",
36
+ "---", ":id: 3", ":parent: 1", ":children:", "- 7", "- 8", ":position: branch1",
37
+ "---", ":id: 4", ":parent: 2", ":children: []", ":position: branch2",
38
+ "---", ":id: 5", ":parent: 2", ":children:", "- 6", ":position: branch3",
39
+ "---", ":id: 6", ":parent: 5", ":children: []", ":position: branch4",
40
+ "---", ":id: 7", ":parent: 3", ":children: []", ":position: leaf1",
41
+ "---", ":id: 8", ":parent: 3", ":children: []", ":position: leaf2"]
42
+ end
43
+
44
+ it "should revive a tree structure from a file" do
45
+ tree_factory
46
+ test_file = File.join(ENV['HOME'],'tempo','tempo_trees.yaml')
47
+ File.delete(test_file) if File.exists?( test_file )
48
+ contents = Tempo::Model::Tree.save_to_file
49
+ Tempo::Model::Tree.clear_all
50
+ Tempo::Model::Tree.read_from_file
51
+ branch1 = Tempo::Model::Tree.find_by_id 3
52
+ branch1.parent.must_equal 1
53
+ branch1.children.must_equal [7,8]
54
+ end
55
+
56
+ it "should have a << child method" do
57
+ tree_factory
58
+ @forest[1] << @forest[2]
59
+ @forest[1].freeze_dry.must_equal({:id=>2, :parent=>:root, :children=>[3,4,5], :position=>"root2"})
60
+ @forest[2].freeze_dry.must_equal({:id=>3, :parent=>2, :children=>[7,8], :position=>"branch1"})
61
+ end
62
+
63
+ it "should have a report method" do
64
+ tree_factory
65
+ forest_array = Tempo::Model::Tree.report_trees
66
+ forest_array.must_equal "[[1,[3,[7,8]]],[2,[4,5,[6]]]]"
67
+ end
68
+
69
+ it "returns childern to root when deleted" do
70
+ tree_factory
71
+ Tempo::Model::Tree.delete @forest[0]
72
+ Tempo::Model::Tree.index.length.must_equal 7
73
+ @forest[2].parent.must_equal :root
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,171 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+
5
+ before do
6
+ # See Rakefile for directory prep and cleanup
7
+ @dir = File.join( Dir.home,"tempo" )
8
+ Dir.mkdir(@dir, 0700) unless File.exists?(@dir)
9
+ end
10
+
11
+ after do
12
+ FileUtils.rm_r(@dir) if File.exists?(@dir)
13
+ end
14
+
15
+ describe "Model::Log" do
16
+
17
+ it "inherits the freeze-dry method" do
18
+ log_factory
19
+ frozen = @log_4.freeze_dry
20
+ frozen.must_equal({ :start_time=>Time.new(2014, 01, 02, 07, 15),
21
+ :id=>1, :message=>"day 2 pet the sheep"})
22
+ end
23
+
24
+ it "inherits the same indexing method" do
25
+ log_factory
26
+ Tempo::Model::MessageLog.index.length.must_equal 6
27
+ end
28
+
29
+ it "should also have a days indexing method" do
30
+ log_factory
31
+ Tempo::Model::MessageLog.days_index.length.must_equal 2
32
+ Tempo::Model::MessageLog.days_index[:"20140101"].length.must_equal 3
33
+ Tempo::Model::MessageLog.days_index[:"20140102"].length.must_equal 3
34
+ end
35
+
36
+ it "creates a file name to save to" do
37
+ log_factory
38
+ date = Time.new(2014,1,1)
39
+ Tempo::Model::MessageLog.file(date).must_equal "20140101.yaml"
40
+ end
41
+
42
+ it "grants children the ability to write to a file" do
43
+ log_factory
44
+ test_dir = File.join(ENV['HOME'],'tempo','tempo_message_logs')
45
+ # FileUtils.rm_r test_dir if File.exists?(test_dir)
46
+ Tempo::Model::MessageLog.save_to_file
47
+ test_file_1 = File.join(test_dir, "20140101.yaml")
48
+ test_file_2 = File.join(test_dir, "20140102.yaml")
49
+ contents = eval_file_as_array( test_file_1 )
50
+ contents.must_equal [ "---", ":start_time: 2014-01-01 07:00:00.000000000 -05:00",
51
+ ":id: 1", ":message: day 1 pet the sheep",
52
+ "---", ":start_time: 2014-01-01 07:30:00.000000000 -05:00",
53
+ ":id: 2", ":message: day 1 drinking coffee, check on the mushrooms",
54
+ "---", ":start_time: 2014-01-01 12:30:00.000000000 -05:00",
55
+ ":id: 3", ":message: day 1 water the bonsai"]
56
+ contents = eval_file_as_array( test_file_2 )
57
+ contents.must_equal [ "---", ":start_time: 2014-01-02 07:15:00.000000000 -05:00",
58
+ ":id: 1", ":message: day 2 pet the sheep",
59
+ "---", ":start_time: 2014-01-02 07:45:00.000000000 -05:00",
60
+ ":id: 2", ":message: day 2 drinking coffee, check on the mushrooms",
61
+ "---", ":start_time: 2014-01-02 12:00:00.000000000 -05:00",
62
+ ":id: 3", ":message: day 2 water the bonsai"]
63
+ end
64
+
65
+ it "grants children ability to read from a file" do
66
+ log_record_factory
67
+ time = Time.new(2014, 1, 1)
68
+ Tempo::Model::MessageLog.read_from_file time
69
+ Tempo::Model::MessageLog.ids( time ).must_equal [1,2,3]
70
+ Tempo::Model::MessageLog.index[0].message.must_equal "day 1 pet the sheep"
71
+ end
72
+
73
+ it "loads the records for a given day" do
74
+ log_record_factory
75
+ time = Time.new(2014, 1, 1)
76
+ Tempo::Model::MessageLog.load_day_record time
77
+ Tempo::Model::MessageLog.ids( time ).must_equal [1,2,3]
78
+ Tempo::Model::MessageLog.index[0].message.must_equal "day 1 pet the sheep"
79
+ end
80
+
81
+ it "loads the records for a the most recent day and return day" do
82
+ log_record_factory
83
+ last_day = Tempo::Model::MessageLog.load_last_day
84
+
85
+ time_1 = Time.new(2014, 1, 1) # should not load
86
+ time_2 = Time.new(2014, 1, 2) # should load
87
+ Tempo::Model::MessageLog.ids( time_1 ).must_equal []
88
+ Tempo::Model::MessageLog.ids( time_2 ).must_equal [1,2,3]
89
+ Tempo::Model::MessageLog.index[0].message.must_equal "day 2 pet the sheep"
90
+ last_day.must_equal Time.new(2014, 1, 2)
91
+ end
92
+
93
+ it "loads the records for a time frame" do
94
+ log_record_factory
95
+ time_1 = Time.new(2014, 1, 1)
96
+ time_2 = Time.new(2014, 1, 2)
97
+
98
+ Tempo::Model::MessageLog.load_days_records time_1, time_2
99
+
100
+ Tempo::Model::MessageLog.ids( time_1 ).must_equal [1,2,3]
101
+ Tempo::Model::MessageLog.ids( time_2 ).must_equal [1,2,3]
102
+ Tempo::Model::MessageLog.index[0].message.must_equal "day 1 pet the sheep"
103
+
104
+ # The index is still being sorted by id
105
+ Tempo::Model::MessageLog.index[1].message.must_equal "day 2 pet the sheep"
106
+ end
107
+
108
+ it "loads the days index before adding new" do
109
+ log_record_factory
110
+ new_record = Tempo::Model::MessageLog.new({ message: "day 1 pet the sheep",
111
+ start_time: Time.new(2014, 1, 2, 7 ) })
112
+ new_record.id.must_equal 4
113
+ end
114
+
115
+ it "gives id as a readable attribute" do
116
+ log_factory
117
+ @log_6.id.must_equal 3
118
+ end
119
+
120
+ it "raises an error on duplicate id" do
121
+ log_factory
122
+ args = { message: "duplicate id",
123
+ start_time: Time.new(2014, 1, 1, 3 ),
124
+ id: 1
125
+ }
126
+ proc { Tempo::Model::MessageLog.new( args ) }.must_raise Tempo::Model::IdentityConflictError
127
+ end
128
+
129
+ it "finds logs by id" do
130
+ log_factory
131
+ search = Tempo::Model::MessageLog.find("id", 2 )
132
+ search.must_equal [ @log_2, @log_5 ]
133
+ end
134
+
135
+ it "has a day_id method" do
136
+ day_id = Tempo::Model::MessageLog.day_id Time.new(2014, 1, 1)
137
+ day_id.must_equal "20140101"
138
+ end
139
+
140
+ it "has a find_by_id using day_id method" do
141
+ log_factory
142
+ search = Tempo::Model::MessageLog.find_by_id( 2, "20140101" )
143
+ search.must_equal @log_2
144
+
145
+ search = Tempo::Model::MessageLog.find_by_id( 2, "20140102" )
146
+ search.must_equal @log_5
147
+ end
148
+
149
+ it "has a find_by_id using time method" do
150
+ log_factory
151
+ search = Tempo::Model::MessageLog.find_by_id( 2, Time.new(2014, 1, 1))
152
+ search.must_equal @log_2
153
+ search = Tempo::Model::MessageLog.find_by_id( 2, Time.new(2014, 1, 2))
154
+ search.must_equal @log_5
155
+ end
156
+
157
+ it "has a sort_by_start_time method" do
158
+ list = Tempo::Model::MessageLog.sort_by_start_time [ @log_5, @log_1, @log_3 ]
159
+ list.must_equal [ @log_1, @log_3, @log_5 ]
160
+ end
161
+
162
+ it "has a delete instance method" do
163
+ log_factory
164
+ @log_1.delete
165
+ Tempo::Model::MessageLog.ids(Time.new(2014,1,1)).must_equal [2,3]
166
+ Tempo::Model::MessageLog.index.must_equal [ @log_4, @log_2, @log_5, @log_3, @log_6 ]
167
+ Tempo::Model::MessageLog.days_index[:"20140101"].length.must_equal 2
168
+ Tempo::Model::MessageLog.days_index[:"20140102"].length.must_equal 3
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,105 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+
5
+ before do
6
+ # See Rakefile for directory prep and cleanup
7
+ @dir = File.join( Dir.home,"tempo" )
8
+ Dir.mkdir(@dir, 0700) unless File.exists?(@dir)
9
+ end
10
+
11
+ describe "Model::Project" do
12
+
13
+ it "inherits readable only id" do
14
+ project_factory
15
+ inherits_attr_read_only?( @project_1, :id ).must_equal true
16
+ end
17
+
18
+ it "has accessible title" do
19
+ project_factory
20
+ has_attr_accessor?( @project_1, :title ).must_equal true
21
+ end
22
+
23
+ it "has readable tags" do
24
+ project_factory
25
+ has_attr_read_only?( @project_1, :tags ).must_equal true
26
+ end
27
+
28
+ it "is taggable with an array of tags" do
29
+ project_factory
30
+ @project_2.tag(["seasonal", "moist"])
31
+ @project_2.tags.must_equal(["farming", "fungi", "moist", "seasonal"])
32
+ end
33
+
34
+ it "is untaggable with an array of tags" do
35
+ project_factory
36
+ @project_3.untag( ["farming", "miniaturization"] )
37
+ @project_3.tags.must_equal(["trees"])
38
+ end
39
+
40
+ it "comes with freeze dry for free" do
41
+ project_factory
42
+ @project_3.freeze_dry.must_equal({:id=>3, :parent=>4, :children=>[],
43
+ :title=>"horticulture - backyard bonsai",
44
+ :tags=>["farming", "miniaturization", "trees"]})
45
+ end
46
+
47
+ it "saves to file a collection of projects" do
48
+ project_factory
49
+ test_file = File.join(ENV['HOME'],'tempo','tempo_projects.yaml')
50
+ Tempo::Model::Project.save_to_file
51
+ contents = eval_file_as_array( test_file )
52
+ contents.must_equal [ "---", ":id: 1", ":parent: :root", ":children: []", ":title: sheep herding", ":tags: []",
53
+ "---", ":id: 2", ":parent: 4", ":children: []", ":title: horticulture - basement mushrooms", ":tags:", "- farming", "- fungi", ":current: true",
54
+ "---", ":id: 3", ":parent: 4", ":children: []", ":title: horticulture - backyard bonsai", ":tags:", "- farming", "- miniaturization", "- trees",
55
+ "---", ":id: 4", ":parent: :root", ":children:", "- 2", "- 3", ":title: gardening", ":tags: []"]
56
+ end
57
+
58
+ it "returns an boolean to the include? method" do
59
+ project_factory
60
+ Tempo::Model::Project.include?("bonsai").must_equal false
61
+ Tempo::Model::Project.include?("horticulture - backyard bonsai").must_equal true
62
+ end
63
+
64
+ it "has a current project getter" do
65
+ project_factory
66
+ Tempo::Model::Project.current.must_equal @project_2
67
+ end
68
+
69
+ it "has a current project setter" do
70
+ project_factory
71
+ Tempo::Model::Project.current = @project_3
72
+ Tempo::Model::Project.current.must_equal @project_3
73
+ end
74
+
75
+ it "has a current boolean method" do
76
+ project_factory
77
+ @project_2.current?.must_equal true
78
+ @project_3.current?.must_equal false
79
+ end
80
+
81
+ it "can not set current to a non-existant project" do
82
+ project_factory
83
+ proc { Tempo::Model::Project.current = Tempo::Model::Base.new }.must_raise ArgumentError
84
+ end
85
+
86
+ it "takes current in args to new instance" do
87
+ project_factory
88
+ project_4 = Tempo::Model::Project.new({ title: 'horticulture - basement mushrooms', current: true})
89
+ Tempo::Model::Project.current.must_equal project_4
90
+ end
91
+
92
+ it "saves current in freeze dry" do
93
+ project_factory
94
+ @project_2.freeze_dry.must_equal({:id=>2, :parent=>4, :children=>[],
95
+ :title=>"horticulture - basement mushrooms",
96
+ :tags=>["farming", "fungi"], :current=>true})
97
+ end
98
+
99
+ it "finds a project by id" do
100
+ project_factory
101
+ project = Tempo::Model::Project.find_by_id(1)
102
+ project.must_equal @project_1
103
+ end
104
+ end
105
+ end