rubyexcel 0.0.7 → 0.0.8

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