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