daru_lite 0.1

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 (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