tempo-cli 0.1.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.
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