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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b8708f78a939f35fc9529dd41df30a084580930
4
- data.tar.gz: a49ecd2eaa4f5565520cb6da994468532d91b3ab
3
+ metadata.gz: afbbc45721fdfc44ce9068c0935b1ad91bd90a0c
4
+ data.tar.gz: edcb00a7df61aee3315c36bfc7252666b31cc6f5
5
5
  SHA512:
6
- metadata.gz: 1379f58cb3098c6e12ed2c755651e629da2156a7e4f5de3a35b7e590c693d3ad74ab19978b5260a8b0f62eec86b4cdff1cf9d8cb667d11805238d9bf5defd6cc
7
- data.tar.gz: 4d9731115926c43cf44a975c6b3dc7dfda4131b756d2ed383d98a7bffaa5d12775fbe4fdbb7d177e7124333693502d99c67940cd9d5482a8d67cde34d83c221a
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.cell_at(address).raw }
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
@@ -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 { |hash, key| hash[key] = Cell.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 cell_at(address)
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, refs = Set.new)
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, refs), eval(expression.right, refs))
45
+ @functions.add(eval(expression.left), eval(expression.right))
40
46
  when Formula::Subtraction
41
- @functions.minus(eval(expression.left, refs), eval(expression.right, refs))
47
+ @functions.minus(eval(expression.left), eval(expression.right))
42
48
  when Formula::Multiplication
43
- @functions.multiply(eval(expression.left, refs), eval(expression.right, refs))
49
+ @functions.multiply(eval(expression.left), eval(expression.right))
44
50
  when Formula::Division
45
- @functions.divide(eval(expression.left, refs), eval(expression.right, refs))
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, refs })
53
+ @functions.send(expression.name.downcase, *expression.arguments.map { |arg| eval arg })
48
54
  when Formula::Reference
49
- if refs.include? expression.address
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, refs }
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.flat_map do |col|
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
@@ -1,8 +1,8 @@
1
1
  class Spreadshit::Cell
2
- attr_reader :raw
2
+ attr_reader :address, :raw
3
3
 
4
- def initialize(raw = "", &expression)
5
- @raw = raw
4
+ def initialize(address, &expression)
5
+ @address = address
6
6
  @observers = Set.new
7
7
  @observed = []
8
8
  update(&expression) if block_given?
@@ -10,11 +10,15 @@ class Spreadshit::Functions
10
10
  end
11
11
 
12
12
  def sum(*args)
13
- to_number args.flatten.map { |arg| to_number(arg) }.reduce(:+)
13
+ to_number number_list(*args).reduce(:+)
14
14
  end
15
15
 
16
16
  def average(*args)
17
- to_number(sum(*args) / args.size.to_f)
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
- average = average(*args)
33
+ mean = average(*args)
30
34
 
31
- args.flatten.map { |arg| to_number(arg) }.reduce(0) do |variance, value|
32
- variance + (value - average) ** 2
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
@@ -1,3 +1,3 @@
1
1
  class Spreadshit
2
- VERSION = "0.1.1"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -13,32 +13,16 @@ class Spreadshit
13
13
  end
14
14
 
15
15
  class SpreadsheetDelegate
16
- def initialize
17
- @cell_updated, @cell_value, @cell_content = Proc.new {}
18
- end
19
-
20
- def cell_updated(&block)
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 cell_value(&block)
29
- if block_given?
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
- draw_cell @sy + row, col
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.1.1
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-19 00:00:00.000000000 Z
11
+ date: 2016-01-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: treetop