rubyexcel 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  RubyExcel
2
2
  =========
3
3
 
4
- Designed for Windows with MS Excel
4
+ Designed for Ruby on Windows with MS Excel
5
5
 
6
- **Still under construction! Bugs are inevitable.**
6
+ Please feel free to log any bugs you find at [GitHub](https://github.com/VirtuosoJoel/RubyExcel/issues "Bug Tracker")
7
7
 
8
8
  Introduction
9
9
  ------------
@@ -97,6 +97,7 @@ Reference a cell's value
97
97
 
98
98
  ```ruby
99
99
  s['A7']
100
+ s.A7
100
101
  s.cell(7,1).value
101
102
  s.range('A7').value
102
103
  s.row(7)['A']
@@ -111,6 +112,8 @@ Reference a group of cells
111
112
  ```ruby
112
113
  s['A1:B3'] #=> Array
113
114
  s.range( 'A1:B3' ) #=> Element
115
+ s.range( 'A:A' ) #=> Element (Column)
116
+ s.range( '1:2' ) #=> Element (Rows)
114
117
  s.range( 'A1', 'B3' ) #=> Element
115
118
  s.range( s.cell( 1, 1 ), s.cell( 3, 2 ) ) #=> Element
116
119
  s.row( 1 ) #=> Row
@@ -118,9 +121,11 @@ s.column( 'A' ) #=> Column
118
121
  s.column( 1 ) #=> Column
119
122
  ```
120
123
 
121
- Detailed Interactions
124
+ Some Examples
122
125
  ========
123
126
 
127
+ This list may be removed in favour of the gem's documentation on rubydoc.
128
+
124
129
  Workbook
125
130
  --------
126
131
 
@@ -561,10 +566,6 @@ s.parent.save_excel( 'Output.xlsx' )
561
566
  Todo List
562
567
  =========
563
568
 
564
- - Allow argument overloading for methods like filter to avoid repetition and increase efficiency.
565
-
566
- - Add support for Range notations like "A:A" and "A:B"
567
-
568
569
  - Write TestCases (after learning how to do it)
569
570
 
570
571
  - Find bugs and extirpate them.
data/lib/rubyexcel.rb CHANGED
@@ -300,6 +300,32 @@ module RubyExcel
300
300
  self
301
301
  end
302
302
 
303
+ # {Sheet#advanced_filter!}
304
+
305
+ def advanced_filter( *args )
306
+ dup.advanced_filter!( *args )
307
+ end
308
+
309
+ # @overload advanced_filter!( header, comparison_operator, search_criteria, ... )
310
+ # Filter on multiple criteria
311
+ #
312
+ # @example Filter to 'Part': 'Type1' and 'Type3', with Qty greater than 1
313
+ # s.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 )
314
+ #
315
+ # @example Filter to 'Part': 'Type1', with 'Ref2' containing 'X'
316
+ # s.advanced_filter!( 'Part', :==, 'Type1', 'Ref2', :include?, 'X' )
317
+ #
318
+ # @param [String] header a header to search under
319
+ # @param [Symbol] comparison_operator the operator to compare with
320
+ # @param [Object] search_criteria the value to filter by
321
+ # @raise [ArgumentError] 'Number of arguments must be a multiple of 3'
322
+ # @raise [ArgumentError] 'Operator must be a symbol'
323
+ #
324
+
325
+ def advanced_filter!( *args )
326
+ data.advanced_filter!( *args ); self
327
+ end
328
+
303
329
  #
304
330
  # Access an Element by indices.
305
331
  #
@@ -432,6 +458,7 @@ module RubyExcel
432
458
  # @yield [Object] the value at the intersection of Column and Row
433
459
  # @return [self]
434
460
  #
461
+
435
462
  def filter!( header, &block )
436
463
  data.filter!( header, &block ); self
437
464
  end
@@ -528,6 +555,35 @@ module RubyExcel
528
555
  end
529
556
  alias maxcolumn maxcol
530
557
 
558
+ #
559
+ # Allow shorthand range references
560
+ #
561
+
562
+ def method_missing(m, *args, &block)
563
+ method_name = m.to_s.upcase.strip
564
+ if method_name =~ /\A[A-Z]{1,3}\d+=?\z/
565
+ if method_name[-1] == '='
566
+ range( method_name.chop ).value = ( args.length == 1 ? args.first : args )
567
+ else
568
+ range( method_name ).value
569
+ end
570
+ else
571
+ super
572
+ end
573
+ end
574
+
575
+ #
576
+ # Allow for certain method_missing calls
577
+ #
578
+
579
+ def respond_to?(meth)
580
+ if meth.to_s.upcase.strip =~ /\A[A-Z]{1,3}\d+=?\z/
581
+ true
582
+ else
583
+ super
584
+ end
585
+ end
586
+
531
587
  #
532
588
  # Split the Sheet into two Sheets by evaluating each value in a column
533
589
  #
@@ -549,6 +605,8 @@ module RubyExcel
549
605
  # @note These are all valid arguments:
550
606
  # ('A1')
551
607
  # ('A1:B2')
608
+ # ('A:A')
609
+ # ('1:1')
552
610
  # ('A1', 'B2')
553
611
  # (cell1)
554
612
  # (cell1, cell2)
@@ -563,7 +621,7 @@ module RubyExcel
563
621
  #
564
622
 
565
623
  def reverse_columns!
566
- data.reverse_columns!
624
+ data.reverse_columns!; self
567
625
  end
568
626
 
569
627
  #
@@ -571,7 +629,7 @@ module RubyExcel
571
629
  #
572
630
 
573
631
  def reverse_rows!
574
- data.reverse_rows!
632
+ data.reverse_rows!; self
575
633
  end
576
634
 
577
635
  #
@@ -75,9 +75,33 @@ module RubyExcel
75
75
 
76
76
  def expand( address )
77
77
  return [[address]] unless address.include? ':'
78
- address.upcase.match( /([A-Z]+)(\d+):([A-Z]+)(\d+)/i )
79
- start_col, end_col, start_row, end_row = [ $1, $3 ].sort + [ $2.to_i, $4.to_i ].sort
78
+
79
+ #Extract the relevant boundaries
80
+ case address
81
+
82
+ # Row
83
+ when /\A(\d+):(\d+)\z/
84
+
85
+ start_col, end_col, start_row, end_row = [ 'A', col_letter( sheet.maxcol ) ] + [ $1.to_i, $2.to_i ].sort
86
+
87
+ # Column
88
+ when /\A([A-Z]+):([A-Z]+)\z/
89
+
90
+ start_col, end_col, start_row, end_row = [ $1, $2 ].sort + [ 1, sheet.maxrow ]
91
+
92
+ # Range
93
+ when /([A-Z]+)(\d+):([A-Z]+)(\d+)/
94
+
95
+ start_col, end_col, start_row, end_row = [ $1, $3 ].sort + [ $2.to_i, $4.to_i ].sort
96
+
97
+ # Invalid
98
+ else
99
+ fail ArgumentError, 'Invalid address: ' + address
100
+ end
101
+
102
+ # Return the array of addresses
80
103
  ( start_row..end_row ).map { |r| ( start_col..end_col ).map { |c| c + r.to_s } }
104
+
81
105
  end
82
106
 
83
107
  #
@@ -34,6 +34,40 @@ require_relative 'address.rb'
34
34
  calc_dimensions
35
35
  end
36
36
 
37
+ # @overload advanced_filter!( header, comparison_operator, search_criteria, ... )
38
+ # Filter on multiple criteria
39
+ #
40
+ # @example Filter to 'Part': 'Type1' and 'Type3', with 'Qty' greater than 1
41
+ # s.advanced_filter!( 'Part', :=~, /Type[13]/, 'Qty', :>, 1 )
42
+ #
43
+ # @example Filter to 'Part': 'Type1', with 'Ref1' containing 'X'
44
+ # s.advanced_filter!( 'Part', :==, 'Type1', 'Ref1', :include?, 'X' )
45
+ #
46
+ # @param [String] header a header to search under
47
+ # @param [Symbol] comparison_operator the operator to compare with
48
+ # @param [Object] search_criteria the value to filter by
49
+ # @raise [ArgumentError] 'Number of arguments must be a multiple of 3'
50
+ # @raise [ArgumentError] 'Operator must be a symbol'
51
+ #
52
+
53
+ def advanced_filter!( *args )
54
+ hrows = sheet.header_rows
55
+ args.length % 3 == 0 or fail ArgumentError, 'Number of arguments must be a multiple of 3'
56
+ 1.step( args.length - 2, 3 ) { |i| args[i].is_a?( Symbol ) or fail ArgumentError, 'Operator must be a symbol: ' + args[i].to_s }
57
+ 0.step( args.length - 3, 3 ) { |i| index_by_header( args[i] ) }
58
+
59
+ @data = @data.select.with_index do |row, i|
60
+ if hrows > i
61
+ true
62
+ else
63
+ args.each_slice(3).map do |h, op, crit|
64
+ row[ index_by_header( h ) - 1 ].send( op, crit )
65
+ end.all?
66
+ end
67
+ end
68
+
69
+ end
70
+
37
71
  #
38
72
  # Returns a copy of the data
39
73
  #
@@ -185,12 +219,11 @@ require_relative 'address.rb'
185
219
  # @return [self]
186
220
  #
187
221
 
188
- def filter!( header )
222
+ def filter( header )
189
223
  hrows = sheet.header_rows
190
224
  idx = index_by_header( header )
191
225
  @data = @data.select.with_index { |row, i| hrows > i || yield( row[ idx -1 ] ) }
192
226
  calc_dimensions
193
- self
194
227
  end
195
228
 
196
229
  #
@@ -1,5 +1,9 @@
1
1
  module RubyExcel
2
2
 
3
+ #
4
+ # A Range or Cell in a Sheet
5
+ #
6
+
3
7
  class Element
4
8
  include Address
5
9
  include Enumerable
@@ -28,7 +32,7 @@ module RubyExcel
28
32
  #
29
33
 
30
34
  def initialize( sheet, addr )
31
- fail ArgumentError, "Invalid range: #{ addr }" unless addr =~ /\A[A-Z]+\d+:[A-Z]+\d+\z|\A[A-Z]+\d+\z/
35
+ fail ArgumentError, "Invalid range: #{ addr }" unless addr =~ /\A[A-Z]{1,3}\d+:[A-Z]{1,3}\d+\z|\A[A-Z]{1,3}\d+\z|\A[A-Z]{1,3}:[A-Z]{1,3}\z|\A\d+:\d+\z/
32
36
  @sheet = sheet
33
37
  @data = sheet.data
34
38
  @address = addr
@@ -41,7 +45,7 @@ module RubyExcel
41
45
  #
42
46
 
43
47
  def delete
44
- data.delete( self )
48
+ data.delete( self ); self
45
49
  end
46
50
 
47
51
  #
@@ -55,7 +55,7 @@ module RubyExcel
55
55
  #
56
56
 
57
57
  def delete
58
- data.delete( self )
58
+ data.delete( self ); self
59
59
  end
60
60
 
61
61
  #
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyexcel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-04-29 00:00:00.000000000 Z
12
+ date: 2013-04-30 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A tabular data structure, mixing Ruby with some of Excel's API style.
15
15
  email: VirtuosoJoel@gmail.com