rspreadsheet 0.2.9 → 0.2.10

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: 6cefcb8b1947902d4008ba3f9a77cbf1789addd1
4
- data.tar.gz: 841b189fbbe35436ff05e92dcd7fe0cfc368cd0f
3
+ metadata.gz: 09a4b24ab468ec79d6c6e0f079ab4e98ff9dd534
4
+ data.tar.gz: 768912df8317bbad53cc0761bb0d23adabb6b976
5
5
  SHA512:
6
- metadata.gz: 69b9f5968540c86671c39cd93efc04f243cf5c441789e60bedd69a6fdc12a68ccf51016021a9a4bd75fffe65c716cadaeaf79289b6d00fedcdfda46973f62898
7
- data.tar.gz: 52eea9086874e653eddab4374c396a82f09741daf55596a5cb393662d4130b25f5273e8664b43134981e5214d2bcfb3ffe9b3b88136c9d6e50a4eaab77f0df15
6
+ metadata.gz: cb06852ec036f391e3b8a3c3ef25a5f0a9111d19e23bb52f37db49b78adb49dd8fb510ad22cc29516c00c2afb1eef5909fba882c9269d8ca10237760f6303592
7
+ data.tar.gz: fafe3fea122b4ff9f13430b69103b2153c5fcaa808f05bf55c2f838f26c3e4a9b3fedf7c728e0820d96ac343979daa0f70e59b9fd4498a76368823f7dab47daa
data/DEVEL_BLOG.md CHANGED
@@ -2,7 +2,7 @@ See [GUIDE.md](GUIDE.md#conventions) for syntax conventions.
2
2
 
3
3
  ## Ideas/wishlist
4
4
 
5
- * In future inntroduce syntax like ``sheet.range('C3:E4')`` for mass operations. Also maybe ``sheet.cells('C3')`` or ``sheet.cells(3, 'C')`` etc.
5
+ * In future inntroduce syntax like `sheet.range('C3:E4')` for mass operations.
6
6
  * Trying to make row Enumerable - perhaps skipping empty or undefined cells.
7
7
  * Maybe insted two syntaxes for accessing cell, we make both of them do the same and return Proxy object which would act either as value or cell.
8
8
  * Document that there is a little distinction betwean RSpreadsheet and RSpreadsheet::Workbook. The former delegates everythink to the other.
@@ -19,6 +19,9 @@ Guiding ideas
19
19
  * all cells and rows only server as proxy. they hold index and worksheet pointer and everytime read or write is done, the xml is newly searched. until there is a xmlnode caching we have no problem
20
20
  * all cells returned for particular coordinates are **always the same object**. This way we have no problem to synchronize changes.
21
21
 
22
+ ## Known Issues
23
+ * currently there is a confusing syntax @worksheet.rows(1).cells[5] which returns a cell object in SIXT column, which is not intended. It is side effecto of Row#cells returning an array
24
+
22
25
  ## Developing this gem
23
26
 
24
27
  ### Automated testing
@@ -35,7 +38,7 @@ Guiding ideas
35
38
  ### Local testing and releasing (to github and rubygems).
36
39
 
37
40
  1. make changes
38
- 2. test if all tests pass (run `bundle exex guard` to test automatically). If not go to 1
41
+ 2. test if all tests pass (run `bundle exec guard` to test automatically). If not go to 1
39
42
  3. build and install locally
40
43
  * ``rake build`` - builds the gem to pkg directory (if something gets wrong, sometimes comit go git gelps)
41
44
  * ``sudo rake install`` - installs gem to local system [^1]
data/README.md CHANGED
@@ -2,22 +2,17 @@
2
2
 
3
3
  [![Build Status](https://api.travis-ci.org/gorn/rspreadsheet.svg?branch=master)](https://travis-ci.org/gorn/rspreadsheet) [![Coverage Status](https://coveralls.io/repos/gorn/rspreadsheet/badge.png)](https://coveralls.io/r/gorn/rspreadsheet)
4
4
 
5
- Manipulating spreadsheets with Ruby. Read, modify, write or create new OpenDocument Spreadsheet files from ruby code.
5
+ Manipulating spreadsheets with Ruby. Read, **modify**, write or create new OpenDocument Spreadsheet files from ruby code.
6
6
 
7
- ## Contibutions, ideas and wishes welcomed
8
-
9
- If you need any help or find a bug please [submit an issue](https://github.com/gorn/rspreadsheet/issues) here. I appreciate any feedback and even if you can not help with code, it is interesting for me to hear from you. Different people have different needs and I want to hear about them. If you are a programmer and you have any ideas, wishes, etc you are welcomed to fork the repository and submit a pull request preferably including a failing test.
7
+ The gem allows you to acces your file and modify any cell of it, **without** touching the rest of the file, which makes it compatible with all advanced features of ODS files (both existing and future ones). You do not have to worry if it supports feature XY, if it does not, it won't touch it. This itself makes it distinct from most of [similar gems](#why-another-opendocument-spreadsheet-gem). Alhought this gem is still in beta stage I use in everyday and it works fine.
10
8
 
11
- Alhought this gem is still in alpha stage I use in my project it and it works fine. Currently I am experimenting with syntax to get stabilized. **Any suggestions regarding the syntax is very welcomed**
12
-
13
9
  ## Examples of usage
14
-
10
+
15
11
  ```ruby
16
12
  require 'rspreadsheet'
17
13
  book = Rspreadsheet.open('./test.ods')
18
14
  sheet = book.worksheets(1)
19
15
 
20
-
21
16
  # get value of a cell B5 (there are more ways to do this)
22
17
  sheet.B5 # => 'cell value'
23
18
  sheet[5,2] # => 'cell value'
@@ -32,12 +27,14 @@ sheet.cells(5,2).value = 1.78
32
27
  sheet.cells(5,2).format.bold = true
33
28
  sheet.cells(5,2).format.background_color = '#FF0000'
34
29
 
35
- # calculating sum of cells in row
30
+ # calculate sum of cells in row
36
31
  sheet.rows(5).cellvalues.sum
37
32
  sheet.rows(5).cells.sum{ |cell| cell.value.to_f }
38
33
 
39
- # iterating over list of people and displaying the data
34
+ # or set formula to a cell
35
+ sheet.A1.formula='=SUM(A2:A9)'
40
36
 
37
+ # iterating over list of people and displaying the data
41
38
  total = 0
42
39
  sheet.rows.each do |row|
43
40
  puts "Sponsor #{row[1]} with email #{row[2]} has donated #{row[3]} USD."
@@ -58,29 +55,36 @@ This is also pubished as Gist **where you can leave you comments and suggestions
58
55
 
59
56
  ## Installation
60
57
 
61
- Add this line to your application's Gemfile:
62
-
63
- gem 'rspreadsheet'
64
-
65
- And then execute (if this fails install bundle gem):
66
-
67
- $ bundle
68
-
69
- Or install it yourself as:
58
+ Gem is on [Rubygems](https://rubygems.org/gems/rspreadsheet) so you can install it by
70
59
 
71
60
  $ gem install rspreadsheet
72
-
73
- gem is hosted on Rubygems - https://rubygems.org/gems/rspreadsheet
74
61
 
75
- If you get this or similar error
62
+ or add <code>gem 'rspreadsheet'</code> to your Gemfile and execute <code>bundle</code>.
63
+
64
+ If you get this error
76
65
 
77
66
  mkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.h
78
67
 
79
68
  then you might not have installed libxml for ruby. I.e. in debian something like <code>sudo aptitude install ruby-libxml</code> or using equivalent command in other package managers.
80
69
 
81
- ## Motivation and Ideas
70
+ ## Contibutions, ideas and wishes welcomed
71
+
72
+ ### Nonprogrammers
73
+ If you need any help or find a bug please [submit an issue](https://github.com/gorn/rspreadsheet/issues) here. I appreciate any feedback and even if you can not help with code, it is interesting for me to hear from you. Different people have different needs and I want to hear about them. If you are a programmer and you have any ideas, wishes, etc you are welcomed to fork the repository and submit a pull request preferably including a failing test.
82
74
 
83
- This project arised from the necessity. Alhought it is not true that there are no ruby gems allowing to acess OpenDOcument spreadsheet, I did not find another decent one which would suit my needs. Most of them also look abandoned and inactive. I have investigated these options:
75
+ Alhought this gem is still in beta stage I use in everyday and it works fine. Currently I am experimenting with syntax to get stabilized. **Any suggestions regarding the syntax is very welcomed**
76
+
77
+ ### Programmers
78
+
79
+ 1. [Fork it](http://github.com/gorn/rspreadsheet/fork)
80
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
81
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
82
+ 4. Push to the branch (`git push origin my-new-feature`)
83
+ 5. Create new Pull Request
84
+
85
+ ## Why another OpenDocument spreadsheet gem?
86
+
87
+ I would be glad to safe myself work, but surprisingly, there are not that many gems for OpenDocument spreadsheets. Most of them also look abandoned and inactive, or can only read or write spreadsheets, but not modify them. I have investigated these options (you might as well):
84
88
 
85
89
  * [ruby-ods](https://github.com/yalab/ruby-ods) - this one seems abandoned, or even as if it never really started
86
90
  * [rodf](https://github.com/thiagoarrais/rodf)- this only serves as builder, it can not read existing files or modify them
@@ -91,15 +95,6 @@ This project arised from the necessity. Alhought it is not true that there are n
91
95
 
92
96
  One of the main ideas is that the manipulation with OpenDOcument files should be forward compatible and as much current data preserving as possible. The parts of the file which are not needed for the change should not be changed. This is different to some of the mentioned gems, which generate the document from scratch, therefore any advanced features present in the original file which are not directly supported are lost.
93
97
 
94
-
95
- ## Contributing
96
-
97
- 1. [Fork it](http://github.com/gorn/rspreadsheet/fork)
98
- 2. Create your feature branch (`git checkout -b my-new-feature`)
99
- 3. Commit your changes (`git commit -am 'Add some feature'`)
100
- 4. Push to the branch (`git push origin my-new-feature`)
101
- 5. Create new Pull Request
102
-
103
98
  ## Further reading
104
99
 
105
100
  * [Advanced Guide](GUIDE.md) how to use the gem
@@ -205,6 +205,7 @@ class Cell < XMLTiedItem
205
205
  remove_all_type_attributes
206
206
  Tools.set_ns_attribute(xmlnode,'table','formula','of:'+formulastring.to_s)
207
207
  end
208
+ def blank?; self.type==:empty or self.type==:unassigned end
208
209
 
209
210
  end
210
211
 
@@ -293,7 +294,6 @@ class CellFormat
293
294
  return nil if cellnode.nil?
294
295
  cellnode.doc.root.find("./office:automatic-styles#{xpath}").first
295
296
  end
296
-
297
297
  end
298
298
 
299
299
  end
@@ -9,15 +9,18 @@ module Rspreadsheet
9
9
  #
10
10
  # @row = @worksheet.rows(5)
11
11
  #
12
- # Mostly you will this object to access row cells
12
+ # Mostly you will this object to access row cells values
13
13
  #
14
- # @row.cells(2) # identical to @worksheet.rows(5).cells(2)
15
- # @row[2] # identical to @worksheet[5,2] or @row.cells(2)
14
+ # @row[2] # identical to @worksheet[5,2] or @row.cells(2).value
16
15
  #
17
- # or manipulate rows
16
+ # or directly row `Cell` objects
17
+ #
18
+ # @row.cells(2) # => identical to @worksheet.rows(5).cells(2)
19
+ #
20
+ # You can use it to manipulate rows
18
21
  #
19
22
  # @row.add_row_above # adds empty row above
20
- # @row.delete # deletes row
23
+ # @row.delete # deletes row
21
24
  #
22
25
  # and shifts all other rows down/up appropriatelly.
23
26
 
@@ -43,12 +46,35 @@ class Row < XMLTiedItem
43
46
 
44
47
  ## @return [String or Float or Date] value of the cell
45
48
  # @param coli [Integer] colum index of the cell
46
- # returns value of the cell at column `coli`
49
+ # returns value of the cell at column `coli`.
50
+ #
51
+ # @row = @worksheet.rows(5) # with cells containing names of months
52
+ # @row[1] # => "January"
53
+ # @row.cells(2).value # => "February"
54
+ # @row[1].class # => String
47
55
  def [](coli); cells(coli).value end
48
- ## @param coli [Integer] colum index of the cell
49
- # @param avalue [String or Float or Date] colum index of the cell
50
- # sets value of the cell at column `coli`
56
+ # @param avalue [Array]
57
+ # sets value of cell in column `coli`
51
58
  def []=(coli,avalue); cells(coli).value=avalue end
59
+ # @param avalue [Array] array with values
60
+ # sets values of cells of row to values from `avalue`. *Attention*: it deletes the rest of row
61
+ #
62
+ # @row = @worksheet.rows(5)
63
+ # @row.values = ["January", "Feb", nil, 4] # => | January | Feb | | 4 |
64
+ # @row[2] = "foo") # => | January | foo | | 4 |
65
+ def cellvalues=(avalue)
66
+ self.truncate
67
+ avalue.each_with_index{ |val,i| self[i+1] = val }
68
+ end
69
+ ## @return [Array
70
+ # return array of cell values
71
+ #
72
+ # @worksheet[3,3] = "text"
73
+ # @worksheet[3,1] = 123
74
+ # @worksheet.rows(3).cellvalues # => [123, nil, "text"]
75
+ def cellvalues
76
+ cells.collect{|c| c.value}
77
+ end
52
78
  # @!endgroup
53
79
 
54
80
  # @!group Other methods
@@ -72,9 +98,6 @@ class Row < XMLTiedItem
72
98
  def add_row_above
73
99
  parent.add_row_above(rowi)
74
100
  end
75
- def cellvalues
76
- cells.collect{|c| c.value}
77
- end
78
101
 
79
102
  # @!group Private methods, which should not be called directly
80
103
  # @private
@@ -11,7 +11,7 @@ module Tools
11
11
  # converts cell adress like 'F12' to pair od integers [row,col]
12
12
  def self.convert_cell_address_to_coordinates(*addr)
13
13
  if addr.length == 1
14
- addr[0].match(/^([A-Za-z]{1,3})(\d{1,8})$/)
14
+ addr[0].to_s.match(/^([A-Za-z]{1,3})(\d{1,8})$/)
15
15
  colname = $~[1]
16
16
  rowname = $~[2].to_i
17
17
  elsif addr.length == 2
@@ -1,3 +1,3 @@
1
1
  module Rspreadsheet
2
- VERSION = "0.2.9"
2
+ VERSION = "0.2.10"
3
3
  end
@@ -63,9 +63,17 @@ class Worksheet
63
63
  def [](*params)
64
64
  cells(*params).andand.value
65
65
  end
66
- # Aets value of the cell given either by row,column integer coordinates of by address. It also sets the type of the cell according to type of the value. For details #see Cell.value=
66
+ # Sets value of the cell given either by row,column integer coordinates of by address.
67
+ # It also sets the type of the cell according to type of the value. For details #see Cell.value=
68
+ # This also allows syntax like
69
+ #
70
+ # @sheet[1] = ['Jan', 'Feb', 'Mar']
67
71
  def []=(*params)
68
- cells(*params[0..-2]).andand.value = params.last
72
+ if (params.size == 2) and params[0].kind_of?(Integer)
73
+ rows(params[0]).cellvalues = params[1]
74
+ else
75
+ cells(*params[0..-2]).andand.value = params.last
76
+ end
69
77
  end
70
78
  # Returns a Cell object placed in row and column or on a Cell on string address
71
79
  # @param [(Integer,Integer), String] either row and column of the cell (i.e. 3,5) or a string containing it address i.e. 'F12'
@@ -64,10 +64,12 @@ class XMLTiedItem < XMLTied
64
64
 
65
65
  end
66
66
 
67
- # abstrac class. All successort MUST implement: prepare_subitem
67
+ # abstract class. All importers MUST implement: prepare_subitem (and delete)
68
68
  # terminology
69
69
  # item, subitem is object from @itemcache (quite often subclass of XMLTiedItem)
70
70
  # node, subnode is LibXML::XML::Node object
71
+ #
72
+ # this class is made to be included, not subclassed - the reason is in delete method which calls super
71
73
  # @private
72
74
 
73
75
  module XMLTiedArray
@@ -94,7 +96,7 @@ module XMLTiedArray
94
96
  def subitem(aindex)
95
97
  aindex = aindex.to_i
96
98
  if aindex.to_i<=0
97
- nil
99
+ nil # TODO> maybe optionally raise 'Item index should be greater then 0'
98
100
  else
99
101
  @itemcache[aindex] ||= prepare_subitem(aindex)
100
102
  end
@@ -109,11 +111,13 @@ module XMLTiedArray
109
111
  end
110
112
 
111
113
  def subitems_array
112
- (1..(find_first_unused_index_respect_repeated(subitem_xml_options)-1)).collect do |i|
114
+ (1..self.size).collect do |i|
113
115
  subitem(i)
114
116
  end
115
117
  end
116
118
 
119
+ def size; find_first_unused_index_respect_repeated(subitem_xml_options)-1 end
120
+
117
121
  def find_subnode_respect_repeated(axmlnode, aindex, options)
118
122
  result1, result2 = find_subnode_with_range_respect_repeated(axmlnode, aindex, options)
119
123
  return result1
@@ -189,6 +193,7 @@ module XMLTiedArray
189
193
 
190
194
  def find_first_unused_index_respect_repeated(options)
191
195
  index = 0
196
+ return 1 if xmlnode.nil?
192
197
  xmlnode.elements.select{|node| node.name == options[:xml_items_node_name]}.each do |node|
193
198
  repeated = (node.attributes[options[:xml_repeated_attribute]] || 1).to_i
194
199
  index = index+repeated
@@ -222,7 +227,7 @@ module XMLTiedArray
222
227
  item.delete # delete item - this destroys its subitems, xmlnode and invalidates it
223
228
  @itemcache.delete(key) # delete the entry from the hash, normally this would mean this ceases to exist, if user does not have reference stored somewhere. Of he does, the object is invalidated anyways
224
229
  end
225
- super # this for example for Row objects calls XMLTiedItem.delete
230
+ super # this for example for Row objects calls XMLTiedItem.delete because Row is subclass of XMLTiedItem
226
231
  end
227
232
 
228
233
  def find_nonempty_subnode_indexes(axmlnode, options)
@@ -238,6 +243,10 @@ module XMLTiedArray
238
243
  return result
239
244
  end
240
245
 
246
+ # truncate the item completely, deleting all its subitems
247
+ def truncate
248
+ subitems.reverse.each{ |subitem| subitem.delete } # reverse je tu jen kvuli performanci, aby to mazal zezadu
249
+ end
241
250
  end
242
251
 
243
252
  end
data/spec/row_spec.rb CHANGED
@@ -11,10 +11,19 @@ describe Rspreadsheet::Row do
11
11
  @c.value = 3
12
12
  @c.value.should == 3
13
13
  end
14
+ it 'allows access to cells using different syntax' do
15
+ @row = @sheet1.rows(1)
16
+ @row.cells(1).value = 77
17
+ @row.cells(1).value.should == 77
18
+ @row.cells.first.value.should == 77
19
+ @row.cells.first.value = 88
20
+ @row.cells(1).value.should == 88
21
+ @row[1]= 99
22
+ @row.cells(1).value.should == 99
23
+ end
14
24
  it 'can be detached and changes to unrepeated if done' do
15
25
  @row = @sheet1.rows(5)
16
26
  @row.xmlnode.andand.name.should_not == 'table-row'
17
-
18
27
  @row2 = @row.detach
19
28
  @row2.xmlnode.name.should == 'table-row'
20
29
  @row2.is_repeated?.should == false
@@ -204,6 +213,44 @@ describe Rspreadsheet::Row do
204
213
  @sheet1.rows(14).should be @row
205
214
  @sheet1.rows(14).cells(1).value.should eq 'data1'
206
215
  end
216
+ it 'has no cells when empty' do
217
+ @row = @sheet1.rows(2)
218
+ @row.cells.size.should == 0
219
+ end
220
+ it 'has 1 cells when assigned to first one' do
221
+ @row = @sheet1.rows(2)
222
+ @row.cells(1).value = 'foo'
223
+ @row.cells.size.should == 1
224
+ end
225
+ it 'can be mass assigned by cellvalues= method' do
226
+ @row = @sheet1.rows(2)
227
+ # @row.size.should == 0
228
+ @row.cellvalues= ['January',nil,3]
229
+ @row.size.should == 3
230
+ @row.cells(1).value.should == 'January'
231
+ @row.cells(2).blank?.should be_truthy
232
+ @row.cells(3).value.should == 3
233
+ @row.cellvalues = [1]
234
+ @row.size.should == 1
235
+ @row.cells(1).value.should == 1
236
+ @row.cells(3).blank?.should be_truthy
237
+ end
238
+ it 'can be mass assigned by sheet[]= method', :focus do
239
+ @sheet1[1] = ['foo','baz']
240
+ end
241
+ it 'cells can be wiped out by truncate method' do
242
+ @row = @sheet1.rows(1)
243
+ @row[1]='data'
244
+ @row[3]='data3'
245
+ @row.size.should == 3
246
+ @row.truncate
247
+ @row.size.should == 0
248
+ end
207
249
  end
208
250
 
209
251
 
252
+
253
+
254
+
255
+
256
+
@@ -39,9 +39,20 @@ describe Rspreadsheet::Worksheet, :focus do
39
39
  @sheet[1,1].should == 'test text'
40
40
  end
41
41
  it 'value stored to A1 is accesible using different syntax' do
42
- @sheet[1,1] = 'test text'
43
- @sheet[1,1].should == 'test text'
44
- @sheet.cells(1,1).value.should == 'test text'
42
+ @sheet[2,2] = 'test text'
43
+ @sheet[2,2].should == 'test text'
44
+ @sheet.B2.should == 'test text'
45
+ @sheet['B2'].should == 'test text'
46
+ @sheet['2','2'].should == 'test text'
47
+ @sheet['2','B'].should == 'test text'
48
+ @sheet[2,'B'].should == 'test text'
49
+ @sheet['B',2].should == 'test text'
50
+ @sheet['B','2'].should == 'test text'
51
+
52
+ @sheet.cells(2,2).value.should == 'test text'
53
+ @sheet.cells('B2').value.should == 'test text'
54
+ @sheet.cells('B','2').value.should == 'test text'
55
+ @sheet.cells(2,'B').value.should == 'test text'
45
56
  end
46
57
  it 'makes Cell object accessible' do
47
58
  @sheet.cells(1,1).value = 'test text'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspreadsheet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.9
4
+ version: 0.2.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jakub A.Těšínský
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-23 00:00:00.000000000 Z
11
+ date: 2015-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: libxml-ruby