spreadshit 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/demo +3 -1
- data/lib/spreadshit.rb +19 -16
- data/lib/spreadshit/cell.rb +3 -3
- data/lib/spreadshit/functions.rb +15 -5
- data/lib/spreadshit/version.rb +1 -1
- data/lib/spreadshit/window.rb +45 -25
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: afbbc45721fdfc44ce9068c0935b1ad91bd90a0c
|
4
|
+
data.tar.gz: edcb00a7df61aee3315c36bfc7252666b31cc6f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f9f27822a3c55cd10b67d7d85397db2311a77f12f365271e18416d2a6bbbf0a962a02553a930a41d12ac2775d11e11af90a849b9f8a75550116fd9e21807a68
|
7
|
+
data.tar.gz: 15838fb7ba9ed67b51c6b8780c33dba4a9b0b1aadd0708555d2b03f8df67cf652ea70c80d7051fd09feb4b4d881c66636664793e084da58032faa69fc9305529
|
data/bin/demo
CHANGED
@@ -29,6 +29,8 @@ end
|
|
29
29
|
window = Spreadshit::Window.new do |delegate|
|
30
30
|
delegate.cell_updated { |address, value| sheet[address] = value }
|
31
31
|
delegate.cell_value { |address| sheet[address] }
|
32
|
-
delegate.cell_content { |address| sheet.
|
32
|
+
delegate.cell_content { |address| sheet.raw(address) }
|
33
|
+
delegate.cell_dependents { |address| sheet.cell(address).send(:observers).map(&:address) }
|
34
|
+
delegate.cell_dependencies { |address| sheet.cell(address).send(:observed).map(&:address) }
|
33
35
|
end
|
34
36
|
window.start
|
data/lib/spreadshit.rb
CHANGED
@@ -1,10 +1,12 @@
|
|
1
|
+
require "matrix"
|
2
|
+
|
1
3
|
class Spreadshit
|
2
4
|
require "spreadshit/cell"
|
3
5
|
require "spreadshit/formula"
|
4
6
|
require "spreadshit/functions"
|
5
7
|
|
6
8
|
def initialize(parser = Formula.new, functions = Functions.new)
|
7
|
-
@cells = Hash.new { |
|
9
|
+
@cells = Hash.new { |cells, address| cells[address] = Cell.new(address) }
|
8
10
|
@parser = parser
|
9
11
|
@functions = functions
|
10
12
|
end
|
@@ -17,7 +19,11 @@ class Spreadshit
|
|
17
19
|
@cells[address.to_sym].update(value) { parse(value) }
|
18
20
|
end
|
19
21
|
|
20
|
-
def
|
22
|
+
def raw(address)
|
23
|
+
@cells[address.to_sym].raw
|
24
|
+
end
|
25
|
+
|
26
|
+
def cell(address)
|
21
27
|
@cells[address.to_sym]
|
22
28
|
end
|
23
29
|
|
@@ -31,37 +37,34 @@ class Spreadshit
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
|
-
def eval(expression
|
40
|
+
def eval(expression)
|
35
41
|
case expression
|
36
42
|
when Formula::Literal
|
37
43
|
expression.content
|
38
44
|
when Formula::Addition
|
39
|
-
@functions.add(eval(expression.left
|
45
|
+
@functions.add(eval(expression.left), eval(expression.right))
|
40
46
|
when Formula::Subtraction
|
41
|
-
@functions.minus(eval(expression.left
|
47
|
+
@functions.minus(eval(expression.left), eval(expression.right))
|
42
48
|
when Formula::Multiplication
|
43
|
-
@functions.multiply(eval(expression.left
|
49
|
+
@functions.multiply(eval(expression.left), eval(expression.right))
|
44
50
|
when Formula::Division
|
45
|
-
@functions.divide(eval(expression.left
|
51
|
+
@functions.divide(eval(expression.left), eval(expression.right))
|
46
52
|
when Formula::Function
|
47
|
-
@functions.send(expression.name.downcase, *expression.arguments.map { |arg| eval arg
|
53
|
+
@functions.send(expression.name.downcase, *expression.arguments.map { |arg| eval arg })
|
48
54
|
when Formula::Reference
|
49
|
-
|
50
|
-
"CYCLIC"
|
51
|
-
else
|
52
|
-
refs << expression.address
|
53
|
-
self[expression.address]
|
54
|
-
end
|
55
|
+
self[expression.address]
|
55
56
|
when Formula::Range
|
56
|
-
expand_range(expression.top, expression.bottom).map { |ref| eval ref
|
57
|
+
expand_range(expression.top, expression.bottom).map { |ref| eval ref }
|
57
58
|
end
|
58
59
|
end
|
59
60
|
|
60
61
|
def expand_range(top, bottom)
|
61
62
|
cols = top.col..bottom.col
|
62
63
|
rows = top.row..bottom.row
|
63
|
-
cols.
|
64
|
+
refs = cols.map do |col|
|
64
65
|
rows.map { |row| Formula::Reference.new(col, row) }
|
65
66
|
end
|
67
|
+
|
68
|
+
Matrix[*refs].transpose
|
66
69
|
end
|
67
70
|
end
|
data/lib/spreadshit/cell.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
class Spreadshit::Cell
|
2
|
-
attr_reader :raw
|
2
|
+
attr_reader :address, :raw
|
3
3
|
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(address, &expression)
|
5
|
+
@address = address
|
6
6
|
@observers = Set.new
|
7
7
|
@observed = []
|
8
8
|
update(&expression) if block_given?
|
data/lib/spreadshit/functions.rb
CHANGED
@@ -10,11 +10,15 @@ class Spreadshit::Functions
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def sum(*args)
|
13
|
-
to_number args
|
13
|
+
to_number number_list(*args).reduce(:+)
|
14
14
|
end
|
15
15
|
|
16
16
|
def average(*args)
|
17
|
-
to_number(sum(*args) / args.
|
17
|
+
to_number(sum(*args) / count(*args).to_f)
|
18
|
+
end
|
19
|
+
|
20
|
+
def count(*args)
|
21
|
+
args.size
|
18
22
|
end
|
19
23
|
|
20
24
|
def sqrt(number)
|
@@ -26,11 +30,13 @@ class Spreadshit::Functions
|
|
26
30
|
end
|
27
31
|
|
28
32
|
def var(*args)
|
29
|
-
|
33
|
+
mean = average(*args)
|
30
34
|
|
31
|
-
|
32
|
-
|
35
|
+
distance_from_mean = number_list(*args).reduce(0) do |total, value|
|
36
|
+
total + (value - mean) ** 2
|
33
37
|
end
|
38
|
+
|
39
|
+
to_number(distance_from_mean / (count(*args) - 1).to_f)
|
34
40
|
end
|
35
41
|
|
36
42
|
def stdev(*args)
|
@@ -65,4 +71,8 @@ class Spreadshit::Functions
|
|
65
71
|
Float::NAN
|
66
72
|
end
|
67
73
|
end
|
74
|
+
|
75
|
+
def number_list(*args)
|
76
|
+
args.map { |item| item.respond_to?(:to_a) ? item.to_a : item }.flatten.map { |arg| to_number arg }
|
77
|
+
end
|
68
78
|
end
|
data/lib/spreadshit/version.rb
CHANGED
data/lib/spreadshit/window.rb
CHANGED
@@ -13,32 +13,16 @@ class Spreadshit
|
|
13
13
|
end
|
14
14
|
|
15
15
|
class SpreadsheetDelegate
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
if block_given?
|
22
|
-
@cell_updated = block
|
23
|
-
else
|
24
|
-
@cell_updated
|
16
|
+
[:cell_updated, :cell_value, :cell_content, :cell_dependents, :cell_dependencies].each do |delegate|
|
17
|
+
define_method delegate do |&block|
|
18
|
+
block ?
|
19
|
+
instance_variable_set("@#{delegate}", block) :
|
20
|
+
instance_variable_get("@#{delegate}")
|
25
21
|
end
|
26
22
|
end
|
27
23
|
|
28
|
-
def
|
29
|
-
|
30
|
-
@cell_value = block
|
31
|
-
else
|
32
|
-
@cell_value
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def cell_content(&block)
|
37
|
-
if block_given?
|
38
|
-
@cell_content = block
|
39
|
-
else
|
40
|
-
@cell_content
|
41
|
-
end
|
24
|
+
def initialize
|
25
|
+
@cell_updated = @cell_value = @cell_value = @cell_dependents = @cell_dependencies = Proc.new {}
|
42
26
|
end
|
43
27
|
end
|
44
28
|
|
@@ -50,6 +34,9 @@ class Spreadshit
|
|
50
34
|
@sx, @sy = 0, 0
|
51
35
|
@col_width = 13
|
52
36
|
@letters = ("A".."ZZZ").to_a
|
37
|
+
|
38
|
+
@show_dependencies = false
|
39
|
+
|
53
40
|
@spreadsheet_delegate = SpreadsheetDelegate.new
|
54
41
|
yield @spreadsheet_delegate
|
55
42
|
end
|
@@ -61,6 +48,8 @@ class Spreadshit
|
|
61
48
|
init_pair(COLOR_BLUE, COLOR_BLACK, COLOR_BLUE)
|
62
49
|
init_pair(COLOR_GREEN, COLOR_BLACK, COLOR_GREEN)
|
63
50
|
init_pair(COLOR_RED, COLOR_BLACK, COLOR_MAGENTA)
|
51
|
+
init_pair(COLOR_YELLOW, COLOR_BLACK, COLOR_YELLOW)
|
52
|
+
init_pair(COLOR_CYAN, COLOR_BLACK, COLOR_CYAN)
|
64
53
|
use_default_colors
|
65
54
|
redraw
|
66
55
|
|
@@ -97,11 +86,22 @@ class Spreadshit
|
|
97
86
|
@spreadsheet_delegate.cell_updated.call(address, value)
|
98
87
|
end
|
99
88
|
|
89
|
+
def current_cell_dependencies
|
90
|
+
@spreadsheet_delegate.cell_dependencies.call(address) || []
|
91
|
+
end
|
92
|
+
|
93
|
+
def current_cell_dependents
|
94
|
+
@spreadsheet_delegate.cell_dependents.call(address) || []
|
95
|
+
end
|
96
|
+
|
100
97
|
def capture_input
|
101
98
|
case @mode
|
102
99
|
when :navigation
|
100
|
+
curs_set(0)
|
103
101
|
navigate
|
104
102
|
when :edit
|
103
|
+
redraw
|
104
|
+
curs_set(2)
|
105
105
|
read_cell_definition
|
106
106
|
end
|
107
107
|
end
|
@@ -129,6 +129,8 @@ class Spreadshit
|
|
129
129
|
@sx += 1 if @x >= max_cols
|
130
130
|
when 10
|
131
131
|
@mode = :edit
|
132
|
+
when "d", "D"
|
133
|
+
@show_dependencies = !@show_dependencies
|
132
134
|
when 27
|
133
135
|
exit 0
|
134
136
|
else
|
@@ -159,10 +161,16 @@ class Spreadshit
|
|
159
161
|
|
160
162
|
case @mode
|
161
163
|
when :navigation
|
164
|
+
dependencies_text = if @show_dependencies
|
165
|
+
" and D to hide dependencies"
|
166
|
+
else
|
167
|
+
" and D to show dependencies"
|
168
|
+
end
|
169
|
+
|
162
170
|
draw_divider(
|
163
171
|
color: color_pair(COLOR_RED) | A_NORMAL,
|
164
172
|
left_text: current_cell_value.to_s,
|
165
|
-
center_text: "Press ENTER to edit #{address}"
|
173
|
+
center_text: "Press ENTER to edit #{address}" + dependencies_text
|
166
174
|
)
|
167
175
|
cursor_to_input_line
|
168
176
|
addstr(current_cell_content.to_s)
|
@@ -212,7 +220,19 @@ class Spreadshit
|
|
212
220
|
draw_cell @sy + row, col
|
213
221
|
end
|
214
222
|
else
|
215
|
-
|
223
|
+
cell_address = Address.new(col, @sy + row).to_sym
|
224
|
+
|
225
|
+
if @show_dependencies && current_cell_dependencies.include?(cell_address)
|
226
|
+
attron(color_pair(COLOR_CYAN) | A_LOW) do
|
227
|
+
draw_cell @sy + row, col
|
228
|
+
end
|
229
|
+
elsif @show_dependencies && current_cell_dependents.include?(cell_address)
|
230
|
+
attron(color_pair(COLOR_YELLOW) | A_LOW) do
|
231
|
+
draw_cell @sy + row, col
|
232
|
+
end
|
233
|
+
else
|
234
|
+
draw_cell @sy + row, col
|
235
|
+
end
|
216
236
|
end
|
217
237
|
end
|
218
238
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spreadshit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rodrigo Navarro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: treetop
|