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