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,179 @@
1
+ describe DaruLite::DataFrame do
2
+ context "#join" do
3
+ before do
4
+ @left = DaruLite::DataFrame.new({
5
+ :id => [1,2,3,4],
6
+ :name => ['Pirate', 'Monkey', 'Ninja', 'Spaghetti']
7
+ })
8
+ @right = DaruLite::DataFrame.new({
9
+ :id => [1,2,3,4],
10
+ :name => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
11
+ })
12
+ @right_many = DaruLite::DataFrame.new({
13
+ :id => [1,1,1,1],
14
+ :name => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
15
+ })
16
+ @empty = DaruLite::DataFrame.new({
17
+ :id => [],
18
+ :name => []
19
+ })
20
+ end
21
+
22
+ it "performs an inner join of two dataframes" do
23
+ answer = DaruLite::DataFrame.new({
24
+ :id_1 => [3,1],
25
+ :name => ['Ninja', 'Pirate'],
26
+ :id_2 => [4,2]
27
+ }, order: [:id_1, :name, :id_2])
28
+ expect(@left.join(@right, how: :inner, on: [:name])).to eq(answer)
29
+ end
30
+
31
+ it "performs an inner join of two dataframes that has one to many mapping" do
32
+ answer = DaruLite::DataFrame.new({
33
+ :name_1 => ['Pirate', 'Pirate', 'Pirate', 'Pirate'],
34
+ :id => [1,1,1,1],
35
+ :name_2 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
36
+ }, order: [:name_1, :id, :name_2])
37
+ expect(@left.join(@right_many, how: :inner, on: [:id])).to eq(answer)
38
+ end
39
+
40
+ it "performs an inner join of two dataframes that has many to one mapping" do
41
+ left_many = @right_many
42
+ right = @left
43
+
44
+ answer = DaruLite::DataFrame.new({
45
+ :name_2 => ['Pirate', 'Pirate', 'Pirate', 'Pirate'],
46
+ :id => [1,1,1,1],
47
+ :name_1 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
48
+ }, order: [:name_1, :id, :name_2])
49
+ expect(left_many.join(right, how: :inner, on: [:id])).to eq(answer)
50
+ end
51
+
52
+ it "performs an inner join of two dataframes that has many to many mapping" do
53
+ @left[:id].recode! { |v| v == 2 ? 1 : v }
54
+ answer = DaruLite::DataFrame.new({
55
+ :name_1 => ['Pirate', 'Pirate', 'Pirate', 'Pirate', 'Monkey', 'Monkey', 'Monkey', 'Monkey'],
56
+ :id => [1,1,1,1,1,1,1,1],
57
+ :name_2 => ['Rutabaga', 'Pirate', 'Darth Vader', 'Ninja', 'Rutabaga', 'Pirate', 'Darth Vader', 'Ninja']
58
+ }, order: [:name_1, :id, :name_2])
59
+ expect(@left.join(@right_many, how: :inner, on: [:id])).to eq(answer)
60
+ end
61
+
62
+ it "performs a full outer join" do
63
+ answer = DaruLite::DataFrame.new({
64
+ :id_1 => [nil,2,3,1,nil,4],
65
+ :name => ["Darth Vader", "Monkey", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
66
+ :id_2 => [3,nil,4,2,1,nil]
67
+ }, order: [:id_1, :name, :id_2])
68
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
69
+ end
70
+
71
+ it "adds a left/right indicator" do
72
+ answer = DaruLite::DataFrame.new({
73
+ :id_1 => [nil,2,3,1,nil,4],
74
+ :name => ["Darth Vader", "Monkey", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
75
+ :id_2 => [3,nil,4,2,1,nil]
76
+ }, order: [:id_1, :name, :id_2])
77
+
78
+ outer = @left.join(@right, how: :outer, on: [:name], indicator: :my_indicator)
79
+ expect(outer[:my_indicator].to_a).to eq [:right_only, :left_only, :both, :both, :right_only, :left_only]
80
+ end
81
+
82
+
83
+ it "performs a full outer join when the right join keys have nils" do
84
+ @right[:name].recode! { |v| v == 'Rutabaga' ? nil : v }
85
+ answer = DaruLite::DataFrame.new({
86
+ :id_1 => [nil, nil,2,3,1,4],
87
+ :name => [nil, "Darth Vader", "Monkey", "Ninja", "Pirate", "Spaghetti"],
88
+ :id_2 => [1,3,nil,4,2,nil]
89
+ }, order: [:id_1, :name, :id_2])
90
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
91
+ end
92
+
93
+ it "performs a full outer join when the left join keys have nils" do
94
+ @left[:name].recode! { |v| v == 'Monkey' ? nil : v }
95
+ answer = DaruLite::DataFrame.new({
96
+ :id_1 => [2,nil,3,1,nil,4],
97
+ :name => [nil, "Darth Vader", "Ninja", "Pirate", "Rutabaga", "Spaghetti"],
98
+ :id_2 => [nil,3,4,2,1,nil]
99
+ }, order: [:id_1, :name, :id_2])
100
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
101
+ end
102
+
103
+ it "performs a full outer join when both left and right join keys have nils" do
104
+ @left[:name].recode! { |v| v == 'Monkey' ? nil : v }
105
+ @right[:name].recode! { |v| v == 'Rutabaga' ? nil : v }
106
+
107
+ answer = DaruLite::DataFrame.new({
108
+ :id_1 => [nil,2,nil,3,1,4],
109
+ :name => [nil, nil, "Darth Vader", "Ninja", "Pirate", "Spaghetti"],
110
+ :id_2 => [1,nil,3,4,2,nil]
111
+ }, order: [:id_1, :name, :id_2])
112
+ expect(@left.join(@right, how: :outer, on: [:name])).to eq(answer)
113
+ end
114
+
115
+ it "performs a left outer join" do
116
+ answer = DaruLite::DataFrame.new({
117
+ :id_1 => [2,3,1,4],
118
+ :name => ["Monkey", "Ninja", "Pirate", "Spaghetti"],
119
+ :id_2 => [nil,4,2,nil]
120
+ }, order: [:id_1, :name, :id_2])
121
+ expect(@left.join(@right, how: :left, on: [:name])).to eq(answer)
122
+ end
123
+
124
+ it "performs a left join with an empty dataframe" do
125
+
126
+ answer = DaruLite::DataFrame.new({
127
+ :id_1 => [2,3,1,4],
128
+ :name => ["Monkey", "Ninja", "Pirate", "Spaghetti"],
129
+ :id_2 => [nil,nil,nil,nil]
130
+ }, order: [:id_1, :name, :id_2])
131
+
132
+ expect(@left.join(@empty, how: :left, on: [:name])).to eq(answer)
133
+ end
134
+
135
+ it "performs a right outer join" do
136
+ answer = DaruLite::DataFrame.new({
137
+ :id_1 => [nil,3,1,nil],
138
+ :name => ["Darth Vader", "Ninja", "Pirate", "Rutabaga"],
139
+ :id_2 => [3,4,2,1]
140
+ }, order: [:id_1, :name, :id_2])
141
+ expect(@left.join(@right, how: :right, on: [:name])).to eq(answer)
142
+ end
143
+
144
+ it "doesn't convert false into nil when joining boolean values" do
145
+ left = DaruLite::DataFrame.new({ key: [1,2,3], left_value: [true, false, true] })
146
+ right = DaruLite::DataFrame.new({ key: [1,2,3], right_value: [true, false, true] })
147
+
148
+ answer = DaruLite::DataFrame.new({
149
+ left_value: [true, false, true],
150
+ key: [1,2,3],
151
+ right_value: [true, false, true]
152
+ }, order: [:left_value, :key, :right_value] )
153
+
154
+ expect(left.join(right, on: [:key], how: :inner)).to eq answer
155
+ end
156
+
157
+ it "raises if :on field are absent in one of dataframes" do
158
+ @right.vectors = DaruLite::Index.new [:id, :other_name]
159
+ expect { @left.join(@right, how: :right, on: [:name]) }.to \
160
+ raise_error(ArgumentError, /Both dataframes expected .* :name/)
161
+
162
+ expect { @left.join(@right, how: :right, on: [:other_name]) }.to \
163
+ raise_error(ArgumentError, /Both dataframes expected .* :other_name/)
164
+ end
165
+
166
+ it "is able to join by several :on fields" do
167
+ @left.gender = ['m', 'f', 'm', nil]
168
+ @right.gender = ['m', 'm', nil, 'f']
169
+
170
+ answer = DaruLite::DataFrame.new({
171
+ id_1: [1],
172
+ name: ['Pirate'],
173
+ gender: ['m'],
174
+ id_2: [2]
175
+ }, order: [:id_1, :name, :gender, :id_2])
176
+ expect(@left.join(@right, how: :inner, on: [:name, :gender])).to eq(answer)
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,347 @@
1
+ describe DaruLite::Core::Query::BoolArray do
2
+ before do
3
+ @klass = DaruLite::Core::Query::BoolArray
4
+ @left = @klass.new([true, true, true, false, false, true])
5
+ @right = @klass.new([false, false, false, false, true, false])
6
+ end
7
+
8
+ context "#&" do
9
+ it "computes and logic of each element in the array" do
10
+ expect(@left & @right).to eq(
11
+ @klass.new([false, false, false, false, false, false]))
12
+ end
13
+ end
14
+
15
+ context "#|" do
16
+ it "computes or logic of each element in arrays" do
17
+ expect(@left | @right).to eq(
18
+ @klass.new([true, true, true, false, true, true]))
19
+ end
20
+ end
21
+
22
+ context "#!" do
23
+ it "computes not logic of each element" do
24
+ expect(!@left).to eq(
25
+ @klass.new([false, false, false, true, true, false])
26
+ )
27
+ end
28
+ end
29
+
30
+ context '#inspect' do
31
+ it 'is reasonable' do
32
+ expect(@left.inspect).to eq "#<DaruLite::Core::Query::BoolArray:#{@left.object_id} bool_arry=[true, true, true, false, false, true]>"
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "Arel-like syntax" do
38
+ describe "comparison operators" do
39
+ describe DaruLite::Vector do
40
+ describe "non-categorical type" do
41
+ before do
42
+ @vector = DaruLite::Vector.new([23,51,1214,352,32,11])
43
+ @comparator = DaruLite::Vector.new([45,22,1214,55,32,9])
44
+ @klass = DaruLite::Core::Query::BoolArray
45
+ end
46
+
47
+ context "#eq" do
48
+ it "accepts scalar value" do
49
+ expect(@vector.eq(352)).to eq(
50
+ @klass.new([false,false,false,true,false,false]))
51
+ end
52
+
53
+ it "accepts vector and compares corrensponding elements" do
54
+ expect(@vector.eq(@comparator)).to eq(
55
+ @klass.new([false,false,true,false,true,false]))
56
+ end
57
+ end
58
+
59
+ context "#not_eq" do
60
+ it "accepts scalar value" do
61
+ expect(@vector.not_eq(51)).to eq(
62
+ @klass.new([true, false, true, true, true, true]))
63
+ end
64
+
65
+ it "accepts vector and compares corrensponding elements" do
66
+ expect(@vector.not_eq(@comparator)).to eq(
67
+ @klass.new([true, true, false, true, false, true]))
68
+ end
69
+ end
70
+
71
+ context "#lt" do
72
+ it "accepts scalar value" do
73
+ expect(@vector.lt(51)).to eq(
74
+ @klass.new([true, false, false, false, true, true]))
75
+ end
76
+
77
+ it "accepts vector and compares corrensponding elements" do
78
+ expect(@vector.lt(@comparator)).to eq(
79
+ @klass.new([true,false,false,false,false,false]))
80
+ end
81
+ end
82
+
83
+ context "#lteq" do
84
+ it "accepts scalar value" do
85
+ expect(@vector.lteq(51)).to eq(
86
+ @klass.new([true, true, false, false, true, true]))
87
+ end
88
+
89
+ it "accepts vector and compares corrensponding elements" do
90
+ expect(@vector.lteq(@comparator)).to eq(
91
+ @klass.new([true,false,true,false,true,false]))
92
+ end
93
+ end
94
+
95
+ context "#mt" do
96
+ it "accepts scalar value" do
97
+ expect(@vector.mt(51)).to eq(
98
+ @klass.new([false, false, true, true, false, false]))
99
+ end
100
+
101
+ it "accepts vector and compares corrensponding elements" do
102
+ expect(@vector.mt(@comparator)).to eq(
103
+ @klass.new([false,true,false,true,false,true]))
104
+ end
105
+ end
106
+
107
+ context "#mteq" do
108
+ it "accepts scalar value" do
109
+ expect(@vector.mteq(51)).to eq(
110
+ @klass.new([false, true, true, true, false, false]))
111
+ end
112
+
113
+ it "accepts vector and compares corrensponding elements" do
114
+ expect(@vector.mteq(@comparator)).to eq(
115
+ @klass.new([false,true,true,true,true,true]))
116
+ end
117
+ end
118
+
119
+ context "#in" do
120
+ it "checks if any of elements in the arg are present in the vector" do
121
+ expect(@vector.in([23,55,1,33,32])).to eq(
122
+ @klass.new([true, false, false, false, true, false]))
123
+ end
124
+ end
125
+ end
126
+
127
+ describe "categorical type" do
128
+ let(:dv) { DaruLite::Vector.new ['e', 'd', 'd', 'x', 'x'],
129
+ categories: ['a', 'x', 'c', 'd', 'e'], type: :category }
130
+ let(:comp) { DaruLite::Vector.new ['a', 'd', 'x', 'e', 'x'],
131
+ categories: ['a', 'x', 'c', 'd', 'e'], type: :category }
132
+ let(:query_bool_class) { DaruLite::Core::Query::BoolArray }
133
+
134
+ context "#eq" do
135
+ context "scalar" do
136
+ subject { dv.eq 'd' }
137
+
138
+ it { is_expected.to be_a query_bool_class }
139
+ its(:to_a) { is_expected.to eq [false, true, true, false, false] }
140
+ end
141
+
142
+ context "vector" do
143
+ subject { dv.eq comp }
144
+
145
+ it { is_expected.to be_a query_bool_class }
146
+ its(:to_a) { is_expected.to eq [false, true, false, false, true] }
147
+ end
148
+ end
149
+
150
+ context "#not_eq" do
151
+ context "scalar" do
152
+ subject { dv.not_eq 'd' }
153
+
154
+ it { is_expected.to be_a query_bool_class }
155
+ its(:to_a) { is_expected.to eq [true, false, false, true, true] }
156
+ end
157
+
158
+ context "vector" do
159
+ subject { dv.not_eq comp }
160
+
161
+ it { is_expected.to be_a query_bool_class }
162
+ its(:to_a) { is_expected.to eq [true, false, true, true, false] }
163
+ end
164
+ end
165
+
166
+ context "#lt" do
167
+ context "scalar" do
168
+ subject { dv.lt 'd' }
169
+
170
+ it { is_expected.to be_a query_bool_class }
171
+ its(:to_a) { is_expected.to eq [false, false, false, true, true] }
172
+ end
173
+
174
+ context "vector" do
175
+ subject { dv.lt comp }
176
+
177
+ it { is_expected.to be_a query_bool_class }
178
+ its(:to_a) { is_expected.to eq [false, false, false, true, false] }
179
+ end
180
+ end
181
+
182
+ context "#lteq" do
183
+ context "scalar" do
184
+ subject { dv.lteq 'd' }
185
+
186
+ it { is_expected.to be_a query_bool_class }
187
+ its(:to_a) { is_expected.to eq [false, true, true, true, true] }
188
+ end
189
+
190
+ context "vector" do
191
+ subject { dv.lteq comp }
192
+
193
+ it { is_expected.to be_a query_bool_class }
194
+ its(:to_a) { is_expected.to eq [false, true, false, true, true] }
195
+ end
196
+ end
197
+
198
+ context "#mt" do
199
+ context "scalar" do
200
+ subject { dv.mt 'd' }
201
+
202
+ it { is_expected.to be_a query_bool_class }
203
+ its(:to_a) { is_expected.to eq [true, false, false, false, false] }
204
+ end
205
+
206
+ context "vector" do
207
+ subject { dv.mt comp }
208
+
209
+ it { is_expected.to be_a query_bool_class }
210
+ its(:to_a) { is_expected.to eq [true, false, true, false, false] }
211
+ end
212
+ end
213
+
214
+ context "#mteq" do
215
+ context "scalar" do
216
+ subject { dv.mteq 'd' }
217
+
218
+ it { is_expected.to be_a query_bool_class }
219
+ its(:to_a) { is_expected.to eq [true, true, true, false, false] }
220
+ end
221
+
222
+ context "vector" do
223
+ subject { dv.mteq comp }
224
+
225
+ it { is_expected.to be_a query_bool_class }
226
+ its(:to_a) { is_expected.to eq [true, true, true, false, true] }
227
+ end
228
+ end
229
+
230
+ # context "#in" do
231
+ # subject { dv.in ['b', 'd'] }
232
+ # it { is_expected.to be_a query_bool_class }
233
+ # its(:to_a) { is_expected.to eq [false, true, true, true, true] }
234
+ # end
235
+ end
236
+ end
237
+ end
238
+
239
+ describe "where clause" do
240
+ context DaruLite::DataFrame do
241
+ before do
242
+ @df = DaruLite::DataFrame.new({
243
+ number: [1,2,3,4,5,6,Float::NAN],
244
+ sym: [:one, :two, :three, :four, :five, :six, :seven],
245
+ names: ['sameer', 'john', 'james', 'omisha', 'priyanka', 'shravan',nil]
246
+ })
247
+ end
248
+
249
+ it "accepts simple single eq statement" do
250
+ answer = DaruLite::DataFrame.new({
251
+ number: [4],
252
+ sym: [:four],
253
+ names: ['omisha']
254
+ }, index: DaruLite::Index.new([3])
255
+ )
256
+ expect(@df.where(@df[:number].eq(4))).to eq(answer)
257
+ end
258
+
259
+ it "accepts somewhat complex comparison operator chaining" do
260
+ answer = DaruLite::DataFrame.new({
261
+ number: [3,4],
262
+ sym: [:three, :four],
263
+ names: ['james', 'omisha']
264
+ }, index: DaruLite::Index.new([2,3]))
265
+ expect(
266
+ @df.where (@df[:names].eq('james') | @df[:sym].eq(:four))
267
+ ).to eq(answer)
268
+ end
269
+
270
+ let(:dv) { DaruLite::Vector.new([1,11,32,Float::NAN,nil]) }
271
+ it "handles empty data" do
272
+ expect(dv.where(dv.lt(14))).to eq(DaruLite::Vector.new([1,11]))
273
+ end
274
+
275
+ it "does not give SystemStackError" do
276
+ v = DaruLite::Vector.new [1]*300_000
277
+ expect { v.where v.eq(1) }.not_to raise_error
278
+ end
279
+ end
280
+
281
+ context DaruLite::Vector do
282
+ context "non-categorical type" do
283
+ before do
284
+ @vector = DaruLite::Vector.new([2,5,1,22,51,4,nil,Float::NAN])
285
+ end
286
+
287
+ it "accepts a simple single statement" do
288
+ expect(@vector.where(@vector.lt(10))).to eq(
289
+ DaruLite::Vector.new([2,5,1,4], index: DaruLite::Index.new([0,1,2,5])))
290
+ end
291
+
292
+ it "accepts somewhat complex operator chaining" do
293
+ expect(@vector.where((@vector.lt(6) | @vector.eq(51)))).to eq(
294
+ DaruLite::Vector.new([2,5,1,51,4], index: DaruLite::Index.new([0,1,2,4,5])))
295
+ end
296
+ end
297
+
298
+ context "categorical type" do
299
+ let(:dv) { DaruLite::Vector.new ['a', 'c', 'x', 'x', 'c'],
300
+ categories: ['a', 'x', 'c'], type: :category }
301
+
302
+ context "simple single statement" do
303
+ subject { dv.where(dv.lt('x')) }
304
+
305
+ it { is_expected.to be_a DaruLite::Vector }
306
+ its(:type) { is_expected.to eq :category }
307
+ its(:to_a) { is_expected.to eq ['a'] }
308
+ its(:'index.to_a') { is_expected.to eq [0] }
309
+ end
310
+
311
+ context "complex operator chaining" do
312
+ subject { dv.where((dv.lt('x') | dv.eq('c'))) }
313
+
314
+ it { is_expected.to be_a DaruLite::Vector }
315
+ its(:type) { is_expected.to eq :category }
316
+ its(:to_a) { is_expected.to eq ['a', 'c', 'c'] }
317
+ its(:'index.to_a') { is_expected.to eq [0, 1, 4] }
318
+ end
319
+
320
+ context "preserve categories" do
321
+ subject { dv.where((dv.lt('x') | dv.eq('c'))) }
322
+
323
+ it { is_expected.to be_a DaruLite::Vector }
324
+ its(:type) { is_expected.to eq :category }
325
+ its(:to_a) { is_expected.to eq ['a', 'c', 'c'] }
326
+ its(:'index.to_a') { is_expected.to eq [0, 1, 4] }
327
+ its(:categories) { is_expected.to eq ['a', 'x', 'c'] }
328
+ end
329
+ end
330
+
331
+ it "preserves name" do
332
+ named_vector = DaruLite::Vector.new([1,2,3], name: 'named')
333
+ expect(named_vector.where(named_vector.lteq(2)).name).to eq('named')
334
+ end
335
+ end
336
+ end
337
+
338
+ describe "apply_where" do
339
+ context "matches regexp with block input" do
340
+ subject { dv.apply_where(dv.match /weeks/) { |x| "#{x.split.first.to_i * 7} days" } }
341
+
342
+ let(:dv) { DaruLite::Vector.new ['3 days', '5 weeks', '2 weeks'] }
343
+
344
+ it { is_expected.to eq(DaruLite::Vector.new ['3 days', '35 days', '14 days']) }
345
+ end
346
+ end
347
+ end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+
3
+ describe '#error' do
4
+ context 'by default' do
5
+ it { expect { DaruLite.error('test') }.to output("test\n").to_stderr_from_any_process }
6
+ end
7
+
8
+ context 'when set to nil' do
9
+ before { DaruLite.error_stream = nil }
10
+ it { expect { DaruLite.error('test') }.not_to output('test').to_stderr_from_any_process }
11
+ end
12
+
13
+ context 'when set to instance of custom class' do
14
+ let(:custom_stream) { double(puts: nil) }
15
+ before { DaruLite.error_stream = custom_stream }
16
+
17
+ it 'calls puts' do
18
+ expect { DaruLite.error('test') }.not_to output('test').to_stderr_from_any_process
19
+ expect(custom_stream).to have_received(:puts).with('test')
20
+ end
21
+ end
22
+ end