spreadshit 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|