daru_lite 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +7 -0
  2. data/.github/ISSUE_TEMPLATE.md +18 -0
  3. data/.github/workflows/ci.yml +33 -0
  4. data/.gitignore +10 -0
  5. data/.rspec +2 -0
  6. data/.rubocop.yml +27 -0
  7. data/.rubocop_todo.yml +137 -0
  8. data/CONTRIBUTING.md +47 -0
  9. data/Gemfile +2 -0
  10. data/History.md +4 -0
  11. data/LICENSE +24 -0
  12. data/README.md +218 -0
  13. data/Rakefile +69 -0
  14. data/ReleasePolicy.md +20 -0
  15. data/benchmarks/TradeoffData.csv +65 -0
  16. data/benchmarks/csv_reading.rb +22 -0
  17. data/benchmarks/dataframe_creation.rb +39 -0
  18. data/benchmarks/db_loading.rb +34 -0
  19. data/benchmarks/duplicating.rb +45 -0
  20. data/benchmarks/group_by.rb +32 -0
  21. data/benchmarks/joining.rb +52 -0
  22. data/benchmarks/row_access.rb +41 -0
  23. data/benchmarks/row_assign.rb +36 -0
  24. data/benchmarks/sorting.rb +51 -0
  25. data/benchmarks/statistics.rb +28 -0
  26. data/benchmarks/vector_access.rb +31 -0
  27. data/benchmarks/vector_assign.rb +42 -0
  28. data/benchmarks/where_clause.rb +48 -0
  29. data/benchmarks/where_vs_filter.rb +28 -0
  30. data/daru_lite.gemspec +55 -0
  31. data/images/README.md +5 -0
  32. data/images/con0.png +0 -0
  33. data/images/con1.png +0 -0
  34. data/images/init0.png +0 -0
  35. data/images/init1.png +0 -0
  36. data/images/man0.png +0 -0
  37. data/images/man1.png +0 -0
  38. data/images/man2.png +0 -0
  39. data/images/man3.png +0 -0
  40. data/images/man4.png +0 -0
  41. data/images/man5.png +0 -0
  42. data/images/man6.png +0 -0
  43. data/lib/daru_lite/accessors/array_wrapper.rb +109 -0
  44. data/lib/daru_lite/accessors/dataframe_by_row.rb +25 -0
  45. data/lib/daru_lite/accessors/mdarray_wrapper.rb +7 -0
  46. data/lib/daru_lite/category.rb +929 -0
  47. data/lib/daru_lite/configuration.rb +34 -0
  48. data/lib/daru_lite/core/group_by.rb +403 -0
  49. data/lib/daru_lite/core/merge.rb +270 -0
  50. data/lib/daru_lite/core/query.rb +109 -0
  51. data/lib/daru_lite/dataframe.rb +3080 -0
  52. data/lib/daru_lite/date_time/index.rb +569 -0
  53. data/lib/daru_lite/date_time/offsets.rb +397 -0
  54. data/lib/daru_lite/exceptions.rb +2 -0
  55. data/lib/daru_lite/extensions/which_dsl.rb +53 -0
  56. data/lib/daru_lite/formatters/table.rb +52 -0
  57. data/lib/daru_lite/helpers/array.rb +53 -0
  58. data/lib/daru_lite/index/categorical_index.rb +201 -0
  59. data/lib/daru_lite/index/index.rb +374 -0
  60. data/lib/daru_lite/index/multi_index.rb +374 -0
  61. data/lib/daru_lite/io/csv/converters.rb +21 -0
  62. data/lib/daru_lite/io/io.rb +294 -0
  63. data/lib/daru_lite/io/sql_data_source.rb +97 -0
  64. data/lib/daru_lite/iruby/helpers.rb +38 -0
  65. data/lib/daru_lite/iruby/templates/dataframe.html.erb +5 -0
  66. data/lib/daru_lite/iruby/templates/dataframe_mi.html.erb +5 -0
  67. data/lib/daru_lite/iruby/templates/dataframe_mi_tbody.html.erb +35 -0
  68. data/lib/daru_lite/iruby/templates/dataframe_mi_thead.html.erb +21 -0
  69. data/lib/daru_lite/iruby/templates/dataframe_tbody.html.erb +28 -0
  70. data/lib/daru_lite/iruby/templates/dataframe_thead.html.erb +21 -0
  71. data/lib/daru_lite/iruby/templates/multi_index.html.erb +12 -0
  72. data/lib/daru_lite/iruby/templates/vector.html.erb +5 -0
  73. data/lib/daru_lite/iruby/templates/vector_mi.html.erb +5 -0
  74. data/lib/daru_lite/iruby/templates/vector_mi_tbody.html.erb +26 -0
  75. data/lib/daru_lite/iruby/templates/vector_mi_thead.html.erb +8 -0
  76. data/lib/daru_lite/iruby/templates/vector_tbody.html.erb +17 -0
  77. data/lib/daru_lite/iruby/templates/vector_thead.html.erb +8 -0
  78. data/lib/daru_lite/maths/arithmetic/dataframe.rb +91 -0
  79. data/lib/daru_lite/maths/arithmetic/vector.rb +117 -0
  80. data/lib/daru_lite/maths/statistics/dataframe.rb +202 -0
  81. data/lib/daru_lite/maths/statistics/vector.rb +1019 -0
  82. data/lib/daru_lite/monkeys.rb +56 -0
  83. data/lib/daru_lite/vector.rb +1678 -0
  84. data/lib/daru_lite/version.rb +3 -0
  85. data/lib/daru_lite.rb +99 -0
  86. data/profile/_base.rb +23 -0
  87. data/profile/df_to_a.rb +10 -0
  88. data/profile/filter.rb +13 -0
  89. data/profile/joining.rb +13 -0
  90. data/profile/sorting.rb +12 -0
  91. data/profile/vector_each_with_index.rb +9 -0
  92. data/profile/vector_new.rb +9 -0
  93. data/spec/accessors/array_wrapper_spec.rb +3 -0
  94. data/spec/category_spec.rb +1741 -0
  95. data/spec/core/group_by_spec.rb +655 -0
  96. data/spec/core/merge_spec.rb +179 -0
  97. data/spec/core/query_spec.rb +347 -0
  98. data/spec/daru_lite_spec.rb +22 -0
  99. data/spec/dataframe_spec.rb +4330 -0
  100. data/spec/date_time/data_spec.rb +197 -0
  101. data/spec/date_time/date_time_index_helper_spec.rb +72 -0
  102. data/spec/date_time/index_spec.rb +588 -0
  103. data/spec/date_time/offsets_spec.rb +465 -0
  104. data/spec/extensions/which_dsl_spec.rb +38 -0
  105. data/spec/fixtures/bank2.dat +200 -0
  106. data/spec/fixtures/boolean_converter_test.csv +5 -0
  107. data/spec/fixtures/countries.json +7794 -0
  108. data/spec/fixtures/duplicates.csv +32 -0
  109. data/spec/fixtures/eciresults.html +394 -0
  110. data/spec/fixtures/empties.dat +2 -0
  111. data/spec/fixtures/empty_rows_test.csv +17 -0
  112. data/spec/fixtures/macau.html +3691 -0
  113. data/spec/fixtures/macd_data.csv +150 -0
  114. data/spec/fixtures/matrix_test.csv +100 -0
  115. data/spec/fixtures/moneycontrol.html +6812 -0
  116. data/spec/fixtures/music_data.tsv +2501 -0
  117. data/spec/fixtures/repeated_fields.csv +7 -0
  118. data/spec/fixtures/sales-funnel.csv +18 -0
  119. data/spec/fixtures/scientific_notation.csv +4 -0
  120. data/spec/fixtures/string_converter_test.csv +5 -0
  121. data/spec/fixtures/strings.dat +2 -0
  122. data/spec/fixtures/test_xls.xls +0 -0
  123. data/spec/fixtures/test_xls_2.xls +0 -0
  124. data/spec/fixtures/url_test.txt~ +0 -0
  125. data/spec/fixtures/valid_markup.html +62 -0
  126. data/spec/fixtures/wiki_climate.html +1243 -0
  127. data/spec/fixtures/wiki_table_info.html +631 -0
  128. data/spec/formatters/table_formatter_spec.rb +137 -0
  129. data/spec/helpers_spec.rb +8 -0
  130. data/spec/index/categorical_index_spec.rb +170 -0
  131. data/spec/index/index_spec.rb +417 -0
  132. data/spec/index/multi_index_spec.rb +680 -0
  133. data/spec/io/io_spec.rb +373 -0
  134. data/spec/io/sql_data_source_spec.rb +56 -0
  135. data/spec/iruby/dataframe_spec.rb +170 -0
  136. data/spec/iruby/helpers_spec.rb +49 -0
  137. data/spec/iruby/multi_index_spec.rb +37 -0
  138. data/spec/iruby/vector_spec.rb +105 -0
  139. data/spec/maths/arithmetic/dataframe_spec.rb +148 -0
  140. data/spec/maths/arithmetic/vector_spec.rb +165 -0
  141. data/spec/maths/statistics/dataframe_spec.rb +178 -0
  142. data/spec/maths/statistics/vector_spec.rb +756 -0
  143. data/spec/monkeys_spec.rb +42 -0
  144. data/spec/shared/vector_display_spec.rb +213 -0
  145. data/spec/spec_helper.rb +87 -0
  146. data/spec/support/database_helper.rb +30 -0
  147. data/spec/support/matchers.rb +5 -0
  148. data/spec/vector_spec.rb +2293 -0
  149. metadata +571 -0
@@ -0,0 +1,588 @@
1
+ include DaruLite
2
+
3
+ describe DateTimeIndex do
4
+ context ".initialize" do
5
+ it "creates DateTimeIndex from Time objects" do
6
+ index = DateTimeIndex.new([
7
+ DateTime.new(2014,7,1),DateTime.new(2014,7,2),
8
+ DateTime.new(2014,7,3),DateTime.new(2014,7,4)])
9
+ expect(index.class).to eq(DateTimeIndex)
10
+ expect(index['2014-7-2']).to eq(1)
11
+ end
12
+
13
+ it "attempts conversion to Time from strings" do
14
+ index = DateTimeIndex.new([
15
+ '2014-7-1','2014-7-2','2014-7-3','2014-7-4'], freq: :infer)
16
+ expect(index.class).to eq(DateTimeIndex)
17
+ expect(index['2014-7-2']).to eq(1)
18
+ end
19
+
20
+ it "tries to automatically infer the frequency of the data" do
21
+ index = DateTimeIndex.new([
22
+ DateTime.new(2012,1,1), DateTime.new(2012,1,2), DateTime.new(2012,1,3),
23
+ DateTime.new(2012,1,4), DateTime.new(2012,1,5)], freq: :infer)
24
+ expect(index.frequency).to eq('D')
25
+ end
26
+
27
+ it "lets setting of string time format" do
28
+ pending
29
+ DaruLite::DateTimeIndex.format = 'some-date-time-format'
30
+ end
31
+ end
32
+
33
+ context '.try_create' do
34
+ it 'creates index from array of dates' do
35
+ index = DateTimeIndex.try_create([
36
+ DateTime.new(2014,7,1),DateTime.new(2014,7,2),
37
+ DateTime.new(2014,7,3),DateTime.new(2014,7,4)])
38
+ expect(index.class).to eq(DateTimeIndex)
39
+ end
40
+
41
+ it 'does not creates index from anything else' do
42
+ index = DateTimeIndex.try_create([:a, :b, :c])
43
+ expect(index).to be_nil
44
+ end
45
+ end
46
+
47
+ context ".date_range" do
48
+ it "creates DateTimeIndex with default options" do
49
+ index = DateTimeIndex.date_range(:start => DateTime.new(2014,5,3),
50
+ :end => DateTime.new(2014,5,10))
51
+
52
+ expect(index).to eq(DateTimeIndex.new([
53
+ DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
54
+ DateTime.new(2014,5,6),DateTime.new(2014,5,7),DateTime.new(2014,5,8),
55
+ DateTime.new(2014,5,9),DateTime.new(2014,5,10)]))
56
+ expect(index.frequency).to eq('D')
57
+ end
58
+
59
+ it "accepts start and end as strings with default options" do
60
+ index = DateTimeIndex.date_range(start: '2014-5-3', end: '2014-5-10')
61
+
62
+ expect(index).to eq(DateTimeIndex.new([
63
+ DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
64
+ DateTime.new(2014,5,6),DateTime.new(2014,5,7),DateTime.new(2014,5,8),
65
+ DateTime.new(2014,5,9),DateTime.new(2014,5,10)]))
66
+ expect(index.frequency).to eq('D')
67
+ end
68
+
69
+ it 'fails on wrong string format' do
70
+ expect{DateTimeIndex.date_range(start: '2014/5/3', end: '2014/5/10')}
71
+ .to raise_error(ArgumentError, /Unacceptable date string/)
72
+ end
73
+
74
+ it "creates DateTimeIndex of per minute frequency between start and end" do
75
+ index = DateTimeIndex.date_range(start: '2015-7-1',freq: 'M', periods: 10)
76
+
77
+ expect(index).to eq(DateTimeIndex.new([
78
+ DateTime.new(2015,7,1,0,0,0),DateTime.new(2015,7,1,0,1,0),DateTime.new(2015,7,1,0,2,0),
79
+ DateTime.new(2015,7,1,0,3,0),DateTime.new(2015,7,1,0,4,0),DateTime.new(2015,7,1,0,5,0),
80
+ DateTime.new(2015,7,1,0,6,0),DateTime.new(2015,7,1,0,7,0),DateTime.new(2015,7,1,0,8,0),
81
+ DateTime.new(2015,7,1,0,9,0)]))
82
+ expect(index.frequency).to eq('M')
83
+ end
84
+
85
+ it "creates a DateTimeIndex of hourly frequency between start and end" do
86
+ index = DateTimeIndex.date_range(start: '2015-7-1',freq: 'H', periods: 10)
87
+
88
+ expect(index).to eq(DateTimeIndex.new([
89
+ DateTime.new(2015,7,1,0,0,0),DateTime.new(2015,7,1,1,0,0),DateTime.new(2015,7,1,2,0,0),
90
+ DateTime.new(2015,7,1,3,0,0),DateTime.new(2015,7,1,4,0,0),DateTime.new(2015,7,1,5,0,0),
91
+ DateTime.new(2015,7,1,6,0,0),DateTime.new(2015,7,1,7,0,0),DateTime.new(2015,7,1,8,0,0),
92
+ DateTime.new(2015,7,1,9,0,0)]))
93
+ expect(index.frequency).to eq('H')
94
+ end
95
+
96
+ it "creates a DateTimeIndex of daily frequency for specified periods" do
97
+ index = DateTimeIndex.date_range(start: '2015-7-29',freq: 'D',periods: 10)
98
+
99
+ expect(index).to eq(DateTimeIndex.new([
100
+ DateTime.new(2015,7,29,0,0,0),DateTime.new(2015,7,30,0,0,0),DateTime.new(2015,7,31,0,0,0),
101
+ DateTime.new(2015,8,1,0,0,0),DateTime.new(2015,8,2,0,0,0),DateTime.new(2015,8,3,0,0,0),
102
+ DateTime.new(2015,8,4,0,0,0),DateTime.new(2015,8,5,0,0,0),DateTime.new(2015,8,6,0,0,0),
103
+ DateTime.new(2015,8,7,0,0,0)]))
104
+ expect(index.frequency).to eq('D')
105
+ end
106
+
107
+ it "creates a DateTimeIndex of (sunday) weekly frequency" do
108
+ index = DateTimeIndex.date_range(start: '2014-8-2', end: '2014-9-8',
109
+ freq: 'W')
110
+
111
+ expect(index).to eq(DateTimeIndex.new([
112
+ DateTime.new(2014,8,3) ,DateTime.new(2014,8,10),DateTime.new(2014,8,17),
113
+ DateTime.new(2014,8,24),DateTime.new(2014,8,31),DateTime.new(2014,9,7)]))
114
+ expect(index.frequency).to eq('W-SUN')
115
+ end
116
+
117
+ it "creates a DateTimeIndex of (monday) weekly frequency" do
118
+ index = DateTimeIndex.date_range(:start => '2015-7-6', :periods => 5,
119
+ :freq => 'W-MON')
120
+ expect(index).to eq(DateTimeIndex.new([
121
+ DateTime.new(2015,7,6), DateTime.new(2015,7,13), DateTime.new(2015,7,20),
122
+ DateTime.new(2015,7,27), DateTime.new(2015,8,3)]))
123
+ expect(index.frequency).to eq('W-MON')
124
+ end
125
+
126
+ it "creates a DateTimeIndex of month begin frequency" do
127
+ index = DateTimeIndex.date_range(
128
+ :start => '2017-4-14', :freq => 'MB', :periods => 5)
129
+ expect(index).to eq(DateTimeIndex.new([
130
+ DateTime.new(2017,5,1), DateTime.new(2017,6,1),
131
+ DateTime.new(2017,7,1), DateTime.new(2017,8,1),DateTime.new(2017,9,1)]))
132
+ end
133
+
134
+ it "creates a DateTimeIndex of month end frequency" do
135
+ index = DateTimeIndex.date_range(
136
+ :start => '2014-2-22', freq: 'ME', periods: 6)
137
+ expect(index).to eq(DateTimeIndex.new([
138
+ DateTime.new(2014,2,28), DateTime.new(2014,3,31), DateTime.new(2014,4,30),
139
+ DateTime.new(2014,5,31), DateTime.new(2014,6,30), DateTime.new(2014,7,31)]))
140
+ end
141
+
142
+ it "creates a DateTimeIndex of year begin frequency" do
143
+ index = DateTimeIndex.date_range(:start => '2014-4-2', periods: 3, freq: 'YB')
144
+ expect(index).to eq(DateTimeIndex.new([
145
+ DateTime.new(2015,1,1), DateTime.new(2016,1,1), DateTime.new(2017,1,1)]))
146
+ end
147
+
148
+ it "creates a DateTimeIndex of year end frequency" do
149
+ index = DateTimeIndex.date_range(start: '2014-9',end: '2018-1',freq: 'YE')
150
+
151
+ expect(index).to eq(DateTimeIndex.new([
152
+ DateTime.new(2014,12,31), DateTime.new(2015,12,31),DateTime.new(2016,12,31),
153
+ DateTime.new(2017,12,31)]))
154
+ expect(index.frequency).to eq('YE')
155
+ end
156
+
157
+ it "creates only specfied number of periods taking precendence over end" do
158
+ index = DateTimeIndex.date_range(start: '2014-5-5', end: '2015-3',
159
+ periods: 5, freq: 'YB')
160
+ expect(index).to eq(DateTimeIndex.new([
161
+ DateTime.new(2015,1,1),DateTime.new(2016,1,1),DateTime.new(2017,1,1),
162
+ DateTime.new(2018,1,1),DateTime.new(2019,1,1)]))
163
+ end
164
+
165
+ it "does not increment start date if it satisifies the anchor" do
166
+ index = DateTimeIndex.date_range(:start => '2012-1-1', freq: 'MB', periods: 4)
167
+ expect(index).to eq(DateTimeIndex.new(
168
+ [DateTime.new(2012,1,1), DateTime.new(2012,2,1),
169
+ DateTime.new(2012,3,1), DateTime.new(2012,4,1)]))
170
+ end
171
+
172
+ it "raises error for different start and end timezones" do
173
+ expect {
174
+ DateTimeIndex.date_range(
175
+ :start => DateTime.new(2012,3,4,12,5,4,"+5:30"),
176
+ :end => DateTime.new(2013,3,4,12,5,4,"+7:30"), freq: 'M')
177
+ }.to raise_error(ArgumentError)
178
+ end
179
+ end
180
+
181
+ context '#inspect' do
182
+ subject { index.inspect }
183
+
184
+ context 'with known frequency' do
185
+ let(:index){
186
+ DateTimeIndex.new([
187
+ DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
188
+ DateTime.new(2014,7,4)], freq: :infer)
189
+ }
190
+ it { is_expected.to eq \
191
+ "#<DaruLite::DateTimeIndex(4, frequency=D) 2014-07-01T00:00:00+00:00...2014-07-04T00:00:00+00:00>"
192
+ }
193
+ end
194
+
195
+ context 'with unknown frequency' do
196
+ let(:index){
197
+ DateTimeIndex.new([
198
+ DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
199
+ DateTime.new(2014,7,4)])
200
+ }
201
+ it { is_expected.to eq \
202
+ "#<DaruLite::DateTimeIndex(4) 2014-07-01T00:00:00+00:00...2014-07-04T00:00:00+00:00>"
203
+ }
204
+ end
205
+
206
+ context 'empty index' do
207
+ let(:index){ DateTimeIndex.new([]) }
208
+ it { is_expected.to eq "#<DaruLite::DateTimeIndex(0)>" }
209
+ end
210
+ end
211
+
212
+ context "#frequency" do
213
+ it "reports the frequency of when a period index is specified" do
214
+ index = DateTimeIndex.new([
215
+ DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
216
+ DateTime.new(2014,7,4)], freq: :infer)
217
+ expect(index.frequency).to eq('D')
218
+ end
219
+
220
+ it "reports frequency as nil for non-periodic index" do
221
+ index = DateTimeIndex.new([
222
+ DateTime.new(2014,7,1),DateTime.new(2014,7,2),DateTime.new(2014,7,3),
223
+ DateTime.new(2014,7,10)], freq: :infer)
224
+ expect(index.frequency).to eq(nil)
225
+ end
226
+ end
227
+
228
+ context "#[]" do
229
+ it "accepts complete time as a string" do
230
+ index = DateTimeIndex.new([
231
+ DateTime.new(2014,3,3),DateTime.new(2014,3,4),DateTime.new(2014,3,5),DateTime.new(2014,3,6)],
232
+ freq: :infer)
233
+ expect(index.frequency).to eq('D')
234
+ expect(index['2014-3-5']).to eq(2)
235
+ end
236
+
237
+ it "accepts complete time as a DateTime object" do
238
+ index = DateTimeIndex.new([
239
+ DateTime.new(2014,3,3),DateTime.new(2014,3,4),DateTime.new(2014,3,5),DateTime.new(2014,3,6)],
240
+ freq: :infer)
241
+ expect(index[DateTime.new(2014,3,6)]).to eq(3)
242
+ end
243
+
244
+ it "accepts only year specified as a string" do
245
+ index = DateTimeIndex.new([
246
+ DateTime.new(2014,5),DateTime.new(2018,6),DateTime.new(2014,7),DateTime.new(2016,7),
247
+ DateTime.new(2015,7),DateTime.new(2013,7)])
248
+ expect(index['2014']).to eq(DateTimeIndex.new([
249
+ DateTime.new(2014,5),DateTime.new(2014,7)]))
250
+ end
251
+
252
+ it 'does not fail on absent data' do
253
+ index = DateTimeIndex.new([
254
+ DateTime.new(2014,5),DateTime.new(2018,6),DateTime.new(2014,7),DateTime.new(2016,7),
255
+ DateTime.new(2013,7)])
256
+ p DateTimeIndex.new([])
257
+ expect(index['2015']).to eq(DateTimeIndex.new([]))
258
+ end
259
+
260
+ it "accepts only year for frequency data" do
261
+ index = DateTimeIndex.date_range(:start => DateTime.new(2012,3,2),
262
+ periods: 1000, freq: '5D')
263
+ expect(index['2012']).to eq(DateTimeIndex.date_range(
264
+ :start => DateTime.new(2012,3,2), :end => DateTime.new(2012,12,27), freq: '5D'))
265
+ end
266
+
267
+ it "accepts year and month specified as a string" do
268
+ index = DateTimeIndex.new([
269
+ DateTime.new(2014,5,3),DateTime.new(2014,5,4),DateTime.new(2014,5,5),
270
+ DateTime.new(2014,6,3),DateTime.new(2014,7,4),DateTime.new(2014,6,5),
271
+ DateTime.new(2014,7,3),DateTime.new(2014,7,4),DateTime.new(2014,7,5)])
272
+ expect(index['2014-6']).to eq(DateTimeIndex.new([
273
+ DateTime.new(2014,6,3),DateTime.new(2014,6,5)]))
274
+ end
275
+
276
+ it "accepts year and month for frequency data" do
277
+ index = DateTimeIndex.date_range(start: '2014-1-1', periods: 100, freq: 'MB')
278
+ expect(index['2015-3']).to eq(14)
279
+ end
280
+
281
+ it "accepts year, month and date specified as a string" do
282
+ index = DateTimeIndex.new([
283
+ DateTime.new(2012,2,28,0,0,1),DateTime.new(2012,2,25,0,0,1),
284
+ DateTime.new(2012,2,29,0,1,1),DateTime.new(2012,2,29,0,1,3),
285
+ DateTime.new(2012,2,29,0,1,5)])
286
+ expect(index['2012-2-29']).to eq(DateTimeIndex.new([
287
+ DateTime.new(2012,2,29,0,1,1),DateTime.new(2012,2,29,0,1,3),
288
+ DateTime.new(2012,2,29,0,1,5)]))
289
+ end
290
+
291
+ it "accepts year, month, date for frequency data" do
292
+ index = DateTimeIndex.date_range(:start => DateTime.new(2012,2,29),
293
+ periods: 1000, freq: 'M')
294
+ expect(index['2012-2-29']).to eq(DateTimeIndex.date_range(
295
+ :start => DateTime.new(2012,2,29),
296
+ :end => DateTime.new(2012,2,29,16,39,00), freq: 'M'))
297
+ end
298
+
299
+ it "accepts year, month, date and specific time as a string" do
300
+ index = DateTimeIndex.date_range(
301
+ :start => DateTime.new(2015,5,3),:end => DateTime.new(2015,5,5), freq: 'M')
302
+ expect(index['2015-5-3 00:04:00']).to eq(4)
303
+ end
304
+
305
+ it "accepts with seconds accuracy" do
306
+ index = DateTimeIndex.date_range(
307
+ :start => DateTime.new(2012,3,2,21,4,2), :end => DateTime.new(2012,3,2,21,5,2),
308
+ :freq => 'S')
309
+ expect(index['2012-3-2 21:04:04']).to eq(2)
310
+ end
311
+
312
+ it "supports completely specified time ranges" do
313
+ index = DateTimeIndex.date_range(start: '2011-4-1', periods: 50, freq: 'D')
314
+ expect(index['2011-4-5'..'2011-5-3']).to eq(
315
+ DateTimeIndex.date_range(:start => '2011-4-5', :end => '2011-5-3', freq: 'D'))
316
+ end
317
+
318
+ it "supports time ranges with only year specified" do
319
+ index = DateTimeIndex.date_range(start: '2011-5-5', periods: 50, freq: 'MONTH')
320
+ expect(index['2011'..'2012']).to eq(
321
+ DateTimeIndex.date_range(:start => '2011-5-5', :end => '2012-12-5',
322
+ :freq => 'MONTH'))
323
+ end
324
+
325
+ it "supports time ranges with year and month specified" do
326
+ index = DateTimeIndex.date_range(:start => '2016-4-3', periods: 100, freq: 'D')
327
+ expect(index['2016-4'..'2016-5']).to eq(
328
+ DateTimeIndex.date_range(:start => '2016-4-3', periods: 59, freq: 'D'))
329
+ end
330
+
331
+ it "supports time range with year, month and date specified" do
332
+ index = DateTimeIndex.date_range(:start => '2015-7-4', :end => '2015-12-3')
333
+ expect(index['2015-7-4'..'2015-9-3']).to eq(
334
+ DateTimeIndex.date_range(:start => '2015-7-4', :end => '2015-9-3'))
335
+ end
336
+
337
+ it "supports time range with year, month, date and hours specified" do
338
+ index = DateTimeIndex.date_range(:start => '2015-4-2', periods: 120, freq: 'H')
339
+ expect(index['2015-4-3 00:00'..'2015-4-3 12:00']).to eq(
340
+ DateTimeIndex.date_range(:start => '2015-4-3', freq: 'H', periods: 13))
341
+ end
342
+
343
+ it "returns slice upto last element if overshoot in partial date" do
344
+ index = DateTimeIndex.date_range(:start => '2012-4-2', periods: 100, freq: 'M')
345
+ expect(index['2012-4-2']).to eq(DateTimeIndex.date_range(
346
+ :start => '2012-4-2', periods: 100, freq: 'M'))
347
+ end
348
+
349
+ it "returns slice upto last element if overshoot in range" do
350
+ index = DateTimeIndex.date_range(:start => '2012-2-2', :periods => 50,
351
+ freq: 'M')
352
+ expect(index['2012'..'2013']).to eq(DateTimeIndex.date_range(
353
+ :start => '2012-2-2',:periods => 50, freq: 'M'))
354
+ end
355
+
356
+ it "returns a slice when given a numeric range" do
357
+ index = DateTimeIndex.date_range(
358
+ :start => DateTime.new(2012,3,1), :periods => 50)
359
+ expect(index[4..10]).to eq(
360
+ DateTimeIndex.date_range(:start => DateTime.new(2012,3,5), :periods => 7))
361
+ end
362
+
363
+ it "raises error if key out of bounds" do
364
+ index = DateTimeIndex.date_range(:start => '2012-1', :periods => 5)
365
+ expect{
366
+ index['2011']
367
+ }.to raise_error(ArgumentError)
368
+ end
369
+
370
+ it "raises error if date not present (exact date)" do
371
+ expect {
372
+ index = DateTimeIndex.date_range(:start => '2011', :periods => 5, :freq => 'MONTH')
373
+ index[DateTime.new(2013,1,4)]
374
+ }.to raise_error(ArgumentError)
375
+ end
376
+
377
+ it "raises error if date not present (string)" do
378
+ expect {
379
+ index = DateTimeIndex.date_range(:start => '2012-2-3', :periods => 10)
380
+ index['2012-2-4 12']
381
+ }.to raise_error(ArgumentError)
382
+ end
383
+
384
+ it "raises error for out of bounds range" do
385
+ expect {
386
+ index = DateTimeIndex.date_range(:start => '2012', :periods => 100)
387
+ index['2001'..'2005']
388
+ }.to raise_error(ArgumentError)
389
+ end
390
+ end
391
+
392
+ context "#pos" do
393
+ let(:idx) do
394
+ described_class.new([
395
+ DateTime.new(2014,3,3),
396
+ DateTime.new(2014,3,4),
397
+ DateTime.new(2014,3,5),
398
+ DateTime.new(2014,3,6)
399
+ ], freq: :infer
400
+ )
401
+ end
402
+
403
+ context "single index" do
404
+ it { expect(idx.pos '2014-3-4').to eq 1 }
405
+ end
406
+
407
+ context "multiple indexes" do
408
+ subject { idx.pos '2014' }
409
+
410
+ it { is_expected.to be_a Array }
411
+ its(:size) { is_expected.to eq 4 }
412
+ it { is_expected.to eq [0, 1, 2, 3] }
413
+ end
414
+
415
+ context "single positional index" do
416
+ it { expect(idx.pos 1).to eq 1 }
417
+ end
418
+
419
+ context "multiple positional indexes" do
420
+ subject { idx.pos 0, 2 }
421
+
422
+ it { is_expected.to be_a Array }
423
+ its(:size) { is_expected.to eq 3 }
424
+ it { is_expected.to eq [0, 1, 2] }
425
+ end
426
+ end
427
+
428
+ context "#subset" do
429
+ let(:idx) do
430
+ described_class.new([
431
+ DateTime.new(2014,3,3),
432
+ DateTime.new(2014,3,4),
433
+ DateTime.new(2014,3,5),
434
+ DateTime.new(2014,3,6)
435
+ ], freq: :infer
436
+ )
437
+ end
438
+
439
+ context "multiple indexes" do
440
+ subject { idx.subset '2014' }
441
+
442
+ it { is_expected.to be_a described_class }
443
+ its(:size) { is_expected.to eq 4 }
444
+ it { is_expected.to eq idx }
445
+ end
446
+
447
+ context "multiple positional indexes" do
448
+ subject { idx.subset 0, 2 }
449
+
450
+ it { is_expected.to be_a described_class }
451
+ its(:size) { is_expected.to eq 3 }
452
+ its(:to_a) { is_expected.to eq [DateTime.new(2014, 3, 3),
453
+ DateTime.new(2014, 3, 4), DateTime.new(2014, 3, 5)] }
454
+ end
455
+ end
456
+
457
+ context "#slice" do
458
+ it "supports both DateTime objects" do
459
+ index = DateTimeIndex.date_range(:start => '2012', :periods => 50,
460
+ :freq => 'M')
461
+ expect(index.slice(DateTime.new(2012,1,1), DateTime.new(2012,1,1,0,6))).to eq(
462
+ DateTimeIndex.date_range(:start => '2012', :periods => 7, :freq => 'M'))
463
+ end
464
+
465
+ it "supports single DateTime object on the left" do
466
+ index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'M')
467
+ expect(index.slice('2012', DateTime.new(2012,1,1,0,20))).to eq(
468
+ DateTimeIndex.date_range(:start => '2012', :periods => 21, :freq => 'M'))
469
+ end
470
+
471
+ it "supports single DateTime object on the right" do
472
+ index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'MONTH')
473
+ expect(index.slice(DateTime.new(2012), '2013')).to eq(
474
+ DateTimeIndex.date_range(:start => '2012', :periods => 24, :freq => 'MONTH'))
475
+ end
476
+
477
+ it "supports two strings" do
478
+ index = DateTimeIndex.date_range(:start => '2012', :periods => 40, :freq => 'MONTH')
479
+ expect(index.slice('2012', '2013')).to eq(
480
+ DateTimeIndex.date_range(:start => '2012', :periods => 24, :freq => 'MONTH'))
481
+
482
+ # FIXME: It works this way now, yet I'm faithfully not sure that is most
483
+ # reasonable behavior. At least MY expectation is "slice(2012, 2013)" returns
484
+ # "from start of 2012 to start of 2013"... Or am I missing something?.. - zverok
485
+ end
486
+ end
487
+
488
+ context "#size" do
489
+ it "returns the size of the DateTimeIndex" do
490
+ index = DateTimeIndex.date_range start: DateTime.new(2014,5,3), periods: 100
491
+ expect(index.size).to eq(100)
492
+ end
493
+ end
494
+
495
+ context "#add" do
496
+ before { skip }
497
+ let(:idx) { DaruLite::Index.new [:a, :b, :c] }
498
+
499
+ context "single index" do
500
+ subject { idx }
501
+ before { idx.add :d }
502
+
503
+ its(:to_a) { is_expected.to eq [:a, :b, :c, :d] }
504
+ end
505
+
506
+ context "mulitple indexes" do
507
+ subject { idx }
508
+ before { idx.add :d, :e }
509
+
510
+ its(:to_a) { is_expected.to eq [:a, :b, :c, :d, :e] }
511
+ end
512
+ end
513
+
514
+ context "#to_a" do
515
+ it "returns an Array of ruby Time objects" do
516
+ index = DateTimeIndex.date_range(
517
+ start: DateTime.new(2012,2,1), :end => DateTime.new(2012,2,4))
518
+ expect(index.to_a).to eq([
519
+ DateTime.new(2012,2,1),DateTime.new(2012,2,2),DateTime.new(2012,2,3),DateTime.new(2012,2,4)])
520
+ end
521
+
522
+ context 'empty index' do
523
+ subject(:index) { DateTimeIndex.new([]) }
524
+ its(:to_a) { is_expected.to eq [] }
525
+ end
526
+ end
527
+
528
+ context "#shift" do
529
+ it "shifts all dates to the future by specified value (with offset)" do
530
+ index = DateTimeIndex.date_range(
531
+ :start => '2012-1-1', :freq => 'MB', :periods => 10)
532
+ expect(index.shift(3)).to eq(DateTimeIndex.date_range(
533
+ :start => '2012-4-1', :freq => 'MB', :periods => 10))
534
+ end
535
+
536
+ it "shifts all dates by the given offset" do
537
+ offset = DaruLite::Offsets::Minute.new
538
+ index = DateTimeIndex.date_range(
539
+ :start => '2012-3-1', :freq => 'D', :periods => 10)
540
+ expect(index.shift(offset)).to eq(
541
+ DateTimeIndex.date_range(
542
+ :start => '2012-3-1 00:01', :freq => 'D', :periods => 10))
543
+ end
544
+ end
545
+
546
+ context "#lag" do
547
+ it "shifts all dates to the past by specified value (with offset)" do
548
+ index = DateTimeIndex.date_range(
549
+ :start => '2012-5-5', :freq => 'D', :periods => 5)
550
+ expect(index.lag(2)).to eq(DateTimeIndex.date_range(
551
+ :start => '2012-5-3', :freq => 'D', :periods => 5))
552
+ end
553
+
554
+ it "lags all dates by the given offset" do
555
+ offset = DaruLite::Offsets::Month.new
556
+ index = DateTimeIndex.date_range(
557
+ :start => '2012-4-5', :freq => 'MONTH', :periods => 10)
558
+ expect(index.lag(offset)).to eq(
559
+ DateTimeIndex.date_range(:start => '2012-3-5', :periods => 10, freq: offset))
560
+ end
561
+ end
562
+
563
+ [:year, :month, :day, :hour, :min, :sec].each do |meth|
564
+ dates = [
565
+ DateTime.new(2012,5,1,12,5,4), DateTime.new(2015,5,1,13,5),
566
+ DateTime.new(2012,8,1,12,5,3), DateTime.new(2015,1,4,16,5,44)
567
+ ]
568
+ curated = dates.inject([]) do |arr, e|
569
+ arr << e.send(meth)
570
+ arr
571
+ end
572
+
573
+ context "##{meth}" do
574
+ it "returns #{meth} of all dates as an Array" do
575
+ index = DateTimeIndex.new(dates)
576
+ expect(index.send(meth)).to eq(curated)
577
+ end
578
+ end
579
+ end
580
+
581
+ context "#include?" do
582
+ it "returns true if an index is present" do
583
+ index = DateTimeIndex.date_range(:start => '2012-1-4', :periods => 100, :freq => 'D')
584
+ expect(index.include?(DateTime.new(2012,1,6))).to eq(true)
585
+ expect(index.include?(DateTime.new(2011,4,2))).to eq(false)
586
+ end
587
+ end
588
+ end