ava_rails_generator 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +19 -0
  3. data/Rakefile +54 -0
  4. data/USAGE +27 -0
  5. data/VERSION +1 -0
  6. data/ava_rails_generator.rb +201 -0
  7. data/templates/001_create_sessions.rb +16 -0
  8. data/templates/002_create_users.rb +20 -0
  9. data/templates/action_view_helper.rb +35 -0
  10. data/templates/action_view_ja.yml +115 -0
  11. data/templates/active_record_ja.yml +66 -0
  12. data/templates/active_support_ja.yml +36 -0
  13. data/templates/ann_back.png +0 -0
  14. data/templates/ann_back02.png +0 -0
  15. data/templates/application.html.erb +35 -0
  16. data/templates/application.js +128 -0
  17. data/templates/application_controller.rb +90 -0
  18. data/templates/application_csv.rb +66 -0
  19. data/templates/application_helper.rb +558 -0
  20. data/templates/application_search.rb +74 -0
  21. data/templates/arrow_h.gif +0 -0
  22. data/templates/arrow_l.png +0 -0
  23. data/templates/arrow_n.gif +0 -0
  24. data/templates/arrow_r.png +0 -0
  25. data/templates/arrow_v.gif +0 -0
  26. data/templates/auth_controller.rb +80 -0
  27. data/templates/bak.png +0 -0
  28. data/templates/btn_back.png +0 -0
  29. data/templates/btn_cancel_cre.png +0 -0
  30. data/templates/btn_cancel_upd.png +0 -0
  31. data/templates/btn_clear.png +0 -0
  32. data/templates/btn_close.png +0 -0
  33. data/templates/btn_complete.png +0 -0
  34. data/templates/btn_confirm_cre.png +0 -0
  35. data/templates/btn_confirm_upd.png +0 -0
  36. data/templates/btn_create.png +0 -0
  37. data/templates/btn_csv.png +0 -0
  38. data/templates/btn_delete.png +0 -0
  39. data/templates/btn_login.png +0 -0
  40. data/templates/btn_new.png +0 -0
  41. data/templates/btn_reenter.png +0 -0
  42. data/templates/btn_reload.png +0 -0
  43. data/templates/btn_reply.png +0 -0
  44. data/templates/btn_search.png +0 -0
  45. data/templates/btn_send.png +0 -0
  46. data/templates/btn_sub01.png +0 -0
  47. data/templates/btn_sub02.png +0 -0
  48. data/templates/btn_upd.png +0 -0
  49. data/templates/btn_upd_cancel.png +0 -0
  50. data/templates/btn_update.png +0 -0
  51. data/templates/btn_xml.png +0 -0
  52. data/templates/bubble_ex_g.png +0 -0
  53. data/templates/bubble_ex_p.png +0 -0
  54. data/templates/bubble_minus.gif +0 -0
  55. data/templates/bubble_plus.gif +0 -0
  56. data/templates/builder.js +136 -0
  57. data/templates/calendar.gif +0 -0
  58. data/templates/csv.rb +997 -0
  59. data/templates/default.css +92 -0
  60. data/templates/footer_a_bak.gif +0 -0
  61. data/templates/footer_m_bak.gif +0 -0
  62. data/templates/footer_w_bak.gif +0 -0
  63. data/templates/form.css +105 -0
  64. data/templates/g_navi_bak.gif +0 -0
  65. data/templates/import.css +13 -0
  66. data/templates/index.html.erb +8 -0
  67. data/templates/jquery-1.4.4.min.js +167 -0
  68. data/templates/jquery-ui-1.8.10.custom.css +573 -0
  69. data/templates/jquery-ui-1.8.10.custom.min.js +782 -0
  70. data/templates/jquery.ui.datepicker-ja.js +23 -0
  71. data/templates/layout.css +938 -0
  72. data/templates/link.gif +0 -0
  73. data/templates/link_t.gif +0 -0
  74. data/templates/login.html.erb +64 -0
  75. data/templates/login_back01.png +0 -0
  76. data/templates/logo.png +0 -0
  77. data/templates/mail.png +0 -0
  78. data/templates/menuTabL.gif +0 -0
  79. data/templates/menuTabR.gif +0 -0
  80. data/templates/navis.gif +0 -0
  81. data/templates/pageTitle_bak.png +0 -0
  82. data/templates/page_bak.gif +0 -0
  83. data/templates/password.html.erb +69 -0
  84. data/templates/pop.png +0 -0
  85. data/templates/prototype.js +6081 -0
  86. data/templates/rails.png +0 -0
  87. data/templates/scaffold.css +110 -0
  88. data/templates/scriptaculous.js +68 -0
  89. data/templates/slider.js +275 -0
  90. data/templates/sound.js +59 -0
  91. data/templates/tip.png +0 -0
  92. data/templates/tolist.png +0 -0
  93. data/templates/top_controller.rb +5 -0
  94. data/templates/translation_ja.yml +30 -0
  95. data/templates/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  96. data/templates/ui-bg_flat_55_fbec88_40x100.png +0 -0
  97. data/templates/ui-bg_glass_75_d0e5f5_1x400.png +0 -0
  98. data/templates/ui-bg_glass_85_dfeffc_1x400.png +0 -0
  99. data/templates/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  100. data/templates/ui-bg_gloss-wave_55_5c9ccc_500x100.png +0 -0
  101. data/templates/ui-bg_inset-hard_100_f5f8f9_1x100.png +0 -0
  102. data/templates/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  103. data/templates/ui-icons_217bc0_256x240.png +0 -0
  104. data/templates/ui-icons_2e83ff_256x240.png +0 -0
  105. data/templates/ui-icons_469bdd_256x240.png +0 -0
  106. data/templates/ui-icons_6da8d5_256x240.png +0 -0
  107. data/templates/ui-icons_cd0a0a_256x240.png +0 -0
  108. data/templates/ui-icons_d8e7f3_256x240.png +0 -0
  109. data/templates/ui-icons_f9bd01_256x240.png +0 -0
  110. data/templates/unittest.js +568 -0
  111. data/templates/user.rb +71 -0
  112. data/templates/user_blue.css +62 -0
  113. data/templates/user_green.css +61 -0
  114. data/templates/user_red.css +61 -0
  115. metadata +254 -0
@@ -0,0 +1,74 @@
1
+ class ApplicationSearch # < ActiveRecord::Base
2
+
3
+ def initialize(params, options = {})
4
+ @param_keyword = params[:keyword]
5
+ @param_sort = params[:sort]
6
+ @param_order = params[:order]
7
+
8
+ @keyword = '%' + @param_keyword.to_s.gsub('%', '\%').gsub('_', '\_').strip + '%'
9
+ @sort = 'id'
10
+ @sort = @param_sort unless @param_sort.blank?
11
+ @order = 'desc'
12
+ @order = 'asc' if @param_order == 'asc'
13
+
14
+ @tag_sort = @sort
15
+ @tag_order = @order
16
+ end
17
+
18
+ attr_accessor :param_keyword
19
+ attr_accessor :param_sort
20
+ attr_accessor :param_order
21
+
22
+ attr_accessor :form
23
+ attr_accessor :keyword
24
+ attr_accessor :orderby
25
+
26
+ attr_accessor :tag_sort
27
+ attr_accessor :tag_order
28
+
29
+ #attr_accessor :sort
30
+ def sort
31
+ @sort
32
+ end
33
+ def sort=(val)
34
+ @sort = val if val
35
+ @orderby = @sort.to_s + ' ' + @order.to_s
36
+ end
37
+
38
+ #attr_accessor :order
39
+ def order
40
+ @order
41
+ end
42
+ def order=(val)
43
+ @order = val if val
44
+ @orderby = @sort.to_s + ' ' + @order.to_s
45
+ end
46
+
47
+ #attr_accessor :default_sort
48
+ def default_sort
49
+ @default_sort
50
+ end
51
+ def default_sort=(val)
52
+ @default_sort = val if val
53
+ @sort = @tag_sort = @default_sort if @param_sort.blank?
54
+ end
55
+
56
+ #attr_accessor :default_order
57
+ def default_order
58
+ @default_order
59
+ end
60
+ def default_order=(val)
61
+ @default_order = val if val
62
+ @order = @tag_order = @default_order if @param_order.blank?
63
+ end
64
+
65
+ def sort(val, val2)
66
+ self.sort = val2 if val == @sort
67
+ end
68
+
69
+ def default(sort, order)
70
+ self.default_sort = sort
71
+ self.default_order = order
72
+ end
73
+
74
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,80 @@
1
+ class AuthController < ApplicationController
2
+ def login
3
+ unless session_get_user.blank?
4
+ flash[:notice] = ""
5
+ redirect_to(top_url)
6
+ return
7
+ end
8
+
9
+ @display_type = DISPLAY_TYPE_SIMPLE
10
+
11
+ if request.post?
12
+ begin
13
+ user = User.authenticate(params[:id], params[:password])
14
+ raise if user.blank?
15
+ session_set_user(user)
16
+ #Log.create(:user_id => user.id, :action => action_name)
17
+ redirect_to(top_url)
18
+ rescue => e
19
+ flash.now[:notice] = t(:error_login)
20
+ #Log.create(:user_id => 0, :action => action_name, :error => params[:id] + " " + t(:error_login) + " " + e.message)
21
+ end
22
+ end
23
+ end
24
+
25
+ def logout
26
+ # begin
27
+ # user = session[:user_id]
28
+ #Log.create(:user_id => user.id, :action => action_name) unless user.blank?
29
+ # rescue
30
+ # end
31
+ session_reset
32
+ redirect_to(root_url)
33
+ end
34
+
35
+ def password
36
+ @display_type = DISPLAY_TYPE_SIMPLE
37
+ @user = User.find(session[:user_id])
38
+ end
39
+
40
+ def change
41
+ @display_type = DISPLAY_TYPE_SIMPLE
42
+
43
+ begin
44
+ @user = User.find(params[:user][:id])
45
+ # redirect_to(:action => :password, :id => @app.user.id) and return unless updated?
46
+
47
+ if request.put?
48
+ @user.attributes=params[:user]
49
+
50
+ if params[:user][:password] != params[:user][:password_confirmation]
51
+ flash[:notice] = t(:error_pwd_match);
52
+ render :action => :password, :status => 400 and return
53
+ end
54
+
55
+ if User.authenticate( @user.account, params[:user][:password_required] ).blank?
56
+ flash[:notice] = t(:error_login)
57
+ render :action => :password, :status => 400 and return
58
+ end
59
+
60
+ User.transaction do
61
+ @update_flag = @user.save!
62
+ flash[:notice] = t(:success_updated, :id => @user.name)
63
+ end
64
+ end
65
+
66
+ rescue
67
+ render :action => :password, :status => 400 and return
68
+ end
69
+ render :action => :password
70
+ end
71
+
72
+ def open_close
73
+ session_set_msg_opn(params[:flag])
74
+ render :text => "" and return
75
+ end
76
+
77
+ protected
78
+ def authorize
79
+ end
80
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,136 @@
1
+ // script.aculo.us builder.js v1.9.0, Thu Dec 23 16:54:48 -0500 2010
2
+
3
+ // Copyright (c) 2005-2010 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us)
4
+ //
5
+ // script.aculo.us is freely distributable under the terms of an MIT-style license.
6
+ // For details, see the script.aculo.us web site: http://script.aculo.us/
7
+
8
+ var Builder = {
9
+ NODEMAP: {
10
+ AREA: 'map',
11
+ CAPTION: 'table',
12
+ COL: 'table',
13
+ COLGROUP: 'table',
14
+ LEGEND: 'fieldset',
15
+ OPTGROUP: 'select',
16
+ OPTION: 'select',
17
+ PARAM: 'object',
18
+ TBODY: 'table',
19
+ TD: 'table',
20
+ TFOOT: 'table',
21
+ TH: 'table',
22
+ THEAD: 'table',
23
+ TR: 'table'
24
+ },
25
+ // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken,
26
+ // due to a Firefox bug
27
+ node: function(elementName) {
28
+ elementName = elementName.toUpperCase();
29
+
30
+ // try innerHTML approach
31
+ var parentTag = this.NODEMAP[elementName] || 'div';
32
+ var parentElement = document.createElement(parentTag);
33
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
34
+ parentElement.innerHTML = "<" + elementName + "></" + elementName + ">";
35
+ } catch(e) {}
36
+ var element = parentElement.firstChild || null;
37
+
38
+ // see if browser added wrapping tags
39
+ if(element && (element.tagName.toUpperCase() != elementName))
40
+ element = element.getElementsByTagName(elementName)[0];
41
+
42
+ // fallback to createElement approach
43
+ if(!element) element = document.createElement(elementName);
44
+
45
+ // abort if nothing could be created
46
+ if(!element) return;
47
+
48
+ // attributes (or text)
49
+ if(arguments[1])
50
+ if(this._isStringOrNumber(arguments[1]) ||
51
+ (arguments[1] instanceof Array) ||
52
+ arguments[1].tagName) {
53
+ this._children(element, arguments[1]);
54
+ } else {
55
+ var attrs = this._attributes(arguments[1]);
56
+ if(attrs.length) {
57
+ try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707
58
+ parentElement.innerHTML = "<" +elementName + " " +
59
+ attrs + "></" + elementName + ">";
60
+ } catch(e) {}
61
+ element = parentElement.firstChild || null;
62
+ // workaround firefox 1.0.X bug
63
+ if(!element) {
64
+ element = document.createElement(elementName);
65
+ for(attr in arguments[1])
66
+ element[attr == 'class' ? 'className' : attr] = arguments[1][attr];
67
+ }
68
+ if(element.tagName.toUpperCase() != elementName)
69
+ element = parentElement.getElementsByTagName(elementName)[0];
70
+ }
71
+ }
72
+
73
+ // text, or array of children
74
+ if(arguments[2])
75
+ this._children(element, arguments[2]);
76
+
77
+ return $(element);
78
+ },
79
+ _text: function(text) {
80
+ return document.createTextNode(text);
81
+ },
82
+
83
+ ATTR_MAP: {
84
+ 'className': 'class',
85
+ 'htmlFor': 'for'
86
+ },
87
+
88
+ _attributes: function(attributes) {
89
+ var attrs = [];
90
+ for(attribute in attributes)
91
+ attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) +
92
+ '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'&quot;') + '"');
93
+ return attrs.join(" ");
94
+ },
95
+ _children: function(element, children) {
96
+ if(children.tagName) {
97
+ element.appendChild(children);
98
+ return;
99
+ }
100
+ if(typeof children=='object') { // array can hold nodes and text
101
+ children.flatten().each( function(e) {
102
+ if(typeof e=='object')
103
+ element.appendChild(e);
104
+ else
105
+ if(Builder._isStringOrNumber(e))
106
+ element.appendChild(Builder._text(e));
107
+ });
108
+ } else
109
+ if(Builder._isStringOrNumber(children))
110
+ element.appendChild(Builder._text(children));
111
+ },
112
+ _isStringOrNumber: function(param) {
113
+ return(typeof param=='string' || typeof param=='number');
114
+ },
115
+ build: function(html) {
116
+ var element = this.node('div');
117
+ $(element).update(html.strip());
118
+ return element.down();
119
+ },
120
+ dump: function(scope) {
121
+ if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope
122
+
123
+ var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " +
124
+ "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " +
125
+ "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+
126
+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+
127
+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+
128
+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/);
129
+
130
+ tags.each( function(tag){
131
+ scope[tag] = function() {
132
+ return Builder.node.apply(Builder, [tag].concat($A(arguments)));
133
+ };
134
+ });
135
+ }
136
+ };
Binary file
@@ -0,0 +1,997 @@
1
+ # CSV -- module for generating/parsing CSV data.
2
+ # Copyright (C) 2000-2004 NAKAMURA, Hiroshi <nakahiro@sarion.co.jp>.
3
+
4
+ # $Id: csv.rb 11708 2007-02-12 23:01:19Z shyouhei $
5
+
6
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
7
+ # redistribute it and/or modify it under the same terms of Ruby's license;
8
+ # either the dual license version in 2003, or any later version.
9
+
10
+ # Copyright (c) 2012 Masaki Ozawa
11
+ # I change processing when a double quotation mark entered. at line 493.
12
+
13
+ class CSV
14
+ class IllegalFormatError < RuntimeError; end
15
+
16
+ # deprecated
17
+ class Cell < String
18
+ def initialize(data = "", is_null = false)
19
+ super(is_null ? "" : data)
20
+ end
21
+
22
+ def data
23
+ to_s
24
+ end
25
+ end
26
+
27
+ # deprecated
28
+ class Row < Array
29
+ end
30
+
31
+ # Open a CSV formatted file for reading or writing.
32
+ #
33
+ # For reading.
34
+ #
35
+ # EXAMPLE 1
36
+ # CSV.open('csvfile.csv', 'r') do |row|
37
+ # p row
38
+ # end
39
+ #
40
+ # EXAMPLE 2
41
+ # reader = CSV.open('csvfile.csv', 'r')
42
+ # row1 = reader.shift
43
+ # row2 = reader.shift
44
+ # if row2.empty?
45
+ # p 'row2 not find.'
46
+ # end
47
+ # reader.close
48
+ #
49
+ # ARGS
50
+ # filename: filename to parse.
51
+ # col_sep: Column separator. ?, by default. If you want to separate
52
+ # fields with semicolon, give ?; here.
53
+ # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you
54
+ # want to separate records with \r, give ?\r here.
55
+ #
56
+ # RETURNS
57
+ # reader instance. To get parse result, see CSV::Reader#each.
58
+ #
59
+ #
60
+ # For writing.
61
+ #
62
+ # EXAMPLE 1
63
+ # CSV.open('csvfile.csv', 'w') do |writer|
64
+ # writer << ['r1c1', 'r1c2']
65
+ # writer << ['r2c1', 'r2c2']
66
+ # writer << [nil, nil]
67
+ # end
68
+ #
69
+ # EXAMPLE 2
70
+ # writer = CSV.open('csvfile.csv', 'w')
71
+ # writer << ['r1c1', 'r1c2'] << ['r2c1', 'r2c2'] << [nil, nil]
72
+ # writer.close
73
+ #
74
+ # ARGS
75
+ # filename: filename to generate.
76
+ # col_sep: Column separator. ?, by default. If you want to separate
77
+ # fields with semicolon, give ?; here.
78
+ # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you
79
+ # want to separate records with \r, give ?\r here.
80
+ #
81
+ # RETURNS
82
+ # writer instance. See CSV::Writer#<< and CSV::Writer#add_row to know how
83
+ # to generate CSV string.
84
+ #
85
+ def CSV.open(path, mode, fs = nil, rs = nil, &block)
86
+ if mode == 'r' or mode == 'rb'
87
+ open_reader(path, mode, fs, rs, &block)
88
+ elsif mode == 'w' or mode == 'wb'
89
+ open_writer(path, mode, fs, rs, &block)
90
+ else
91
+ raise ArgumentError.new("'mode' must be 'r', 'rb', 'w', or 'wb'")
92
+ end
93
+ end
94
+
95
+ def CSV.foreach(path, rs = nil, &block)
96
+ open_reader(path, 'r', ',', rs, &block)
97
+ end
98
+
99
+ def CSV.read(path, length = nil, offset = nil)
100
+ CSV.parse(IO.read(path, length, offset))
101
+ end
102
+
103
+ def CSV.readlines(path, rs = nil)
104
+ reader = open_reader(path, 'r', ',', rs)
105
+ begin
106
+ reader.collect { |row| row }
107
+ ensure
108
+ reader.close
109
+ end
110
+ end
111
+
112
+ def CSV.generate(path, fs = nil, rs = nil, &block)
113
+ open_writer(path, 'w', fs, rs, &block)
114
+ end
115
+
116
+ # Parse lines from given string or stream. Return rows as an Array of Arrays.
117
+ def CSV.parse(str_or_readable, fs = nil, rs = nil, &block)
118
+ if File.exist?(str_or_readable)
119
+ STDERR.puts("CSV.parse(filename) is deprecated." +
120
+ " Use CSV.open(filename, 'r') instead.")
121
+ return open_reader(str_or_readable, 'r', fs, rs, &block)
122
+ end
123
+ if block
124
+ CSV::Reader.parse(str_or_readable, fs, rs) do |row|
125
+ yield(row)
126
+ end
127
+ nil
128
+ else
129
+ CSV::Reader.create(str_or_readable, fs, rs).collect { |row| row }
130
+ end
131
+ end
132
+
133
+ # Parse a line from given string. Bear in mind it parses ONE LINE. Rest of
134
+ # the string is ignored for example "a,b\r\nc,d" => ['a', 'b'] and the
135
+ # second line 'c,d' is ignored.
136
+ #
137
+ # If you don't know whether a target string to parse is exactly 1 line or
138
+ # not, use CSV.parse_row instead of this method.
139
+ def CSV.parse_line(src, fs = nil, rs = nil)
140
+ fs ||= ','
141
+ if fs.is_a?(Fixnum)
142
+ fs = fs.chr
143
+ end
144
+ if !rs.nil? and rs.is_a?(Fixnum)
145
+ rs = rs.chr
146
+ end
147
+ idx = 0
148
+ res_type = :DT_COLSEP
149
+ row = []
150
+ begin
151
+ while res_type == :DT_COLSEP
152
+ res_type, idx, cell = parse_body(src, idx, fs, rs)
153
+ row << cell
154
+ end
155
+ rescue IllegalFormatError
156
+ return []
157
+ end
158
+ row
159
+ end
160
+
161
+ # Create a line from cells. each cell is stringified by to_s.
162
+ def CSV.generate_line(row, fs = nil, rs = nil)
163
+ if row.size == 0
164
+ return ''
165
+ end
166
+ fs ||= ','
167
+ if fs.is_a?(Fixnum)
168
+ fs = fs.chr
169
+ end
170
+ if !rs.nil? and rs.is_a?(Fixnum)
171
+ rs = rs.chr
172
+ end
173
+ res_type = :DT_COLSEP
174
+ result_str = ''
175
+ idx = 0
176
+ while true
177
+ generate_body(row[idx], result_str, fs, rs)
178
+ idx += 1
179
+ if (idx == row.size)
180
+ break
181
+ end
182
+ generate_separator(:DT_COLSEP, result_str, fs, rs)
183
+ end
184
+ result_str
185
+ end
186
+
187
+ # Parse a line from string. Consider using CSV.parse_line instead.
188
+ # To parse lines in CSV string, see EXAMPLE below.
189
+ #
190
+ # EXAMPLE
191
+ # src = "a,b\r\nc,d\r\ne,f"
192
+ # idx = 0
193
+ # begin
194
+ # parsed = []
195
+ # parsed_cells, idx = CSV.parse_row(src, idx, parsed)
196
+ # puts "Parsed #{ parsed_cells } cells."
197
+ # p parsed
198
+ # end while parsed_cells > 0
199
+ #
200
+ # ARGS
201
+ # src: a CSV data to be parsed. Must respond '[](idx)'.
202
+ # src[](idx) must return a char. (Not a string such as 'a', but 97).
203
+ # src[](idx_out_of_bounds) must return nil. A String satisfies this
204
+ # requirement.
205
+ # idx: index of parsing location of 'src'. 0 origin.
206
+ # out_dev: buffer for parsed cells. Must respond '<<(aString)'.
207
+ # col_sep: Column separator. ?, by default. If you want to separate
208
+ # fields with semicolon, give ?; here.
209
+ # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you
210
+ # want to separate records with \r, give ?\r here.
211
+ #
212
+ # RETURNS
213
+ # parsed_cells: num of parsed cells.
214
+ # idx: index of next parsing location of 'src'.
215
+ #
216
+ def CSV.parse_row(src, idx, out_dev, fs = nil, rs = nil)
217
+ fs ||= ','
218
+ if fs.is_a?(Fixnum)
219
+ fs = fs.chr
220
+ end
221
+ if !rs.nil? and rs.is_a?(Fixnum)
222
+ rs = rs.chr
223
+ end
224
+ idx_backup = idx
225
+ parsed_cells = 0
226
+ res_type = :DT_COLSEP
227
+ begin
228
+ while res_type != :DT_ROWSEP
229
+ res_type, idx, cell = parse_body(src, idx, fs, rs)
230
+ if res_type == :DT_EOS
231
+ if idx == idx_backup #((parsed_cells == 0) and cell.nil?)
232
+ return 0, 0
233
+ end
234
+ res_type = :DT_ROWSEP
235
+ end
236
+ parsed_cells += 1
237
+ out_dev << cell
238
+ end
239
+ rescue IllegalFormatError
240
+ return 0, 0
241
+ end
242
+ return parsed_cells, idx
243
+ end
244
+
245
+ # Convert a line from cells data to string. Consider using CSV.generate_line
246
+ # instead. To generate multi-row CSV string, see EXAMPLE below.
247
+ #
248
+ # EXAMPLE
249
+ # row1 = ['a', 'b']
250
+ # row2 = ['c', 'd']
251
+ # row3 = ['e', 'f']
252
+ # src = [row1, row2, row3]
253
+ # buf = ''
254
+ # src.each do |row|
255
+ # parsed_cells = CSV.generate_row(row, 2, buf)
256
+ # puts "Created #{ parsed_cells } cells."
257
+ # end
258
+ # p buf
259
+ #
260
+ # ARGS
261
+ # src: an Array of String to be converted to CSV string. Must respond to
262
+ # 'size' and '[](idx)'. src[idx] must return String.
263
+ # cells: num of cells in a line.
264
+ # out_dev: buffer for generated CSV string. Must respond to '<<(string)'.
265
+ # col_sep: Column separator. ?, by default. If you want to separate
266
+ # fields with semicolon, give ?; here.
267
+ # row_sep: Row separator. nil by default. nil means "\r\n or \n". If you
268
+ # want to separate records with \r, give ?\r here.
269
+ #
270
+ # RETURNS
271
+ # parsed_cells: num of converted cells.
272
+ #
273
+ def CSV.generate_row(src, cells, out_dev, fs = nil, rs = nil)
274
+ fs ||= ','
275
+ if fs.is_a?(Fixnum)
276
+ fs = fs.chr
277
+ end
278
+ if !rs.nil? and rs.is_a?(Fixnum)
279
+ rs = rs.chr
280
+ end
281
+ src_size = src.size
282
+ if (src_size == 0)
283
+ if cells == 0
284
+ generate_separator(:DT_ROWSEP, out_dev, fs, rs)
285
+ end
286
+ return 0
287
+ end
288
+ res_type = :DT_COLSEP
289
+ parsed_cells = 0
290
+ generate_body(src[parsed_cells], out_dev, fs, rs)
291
+ parsed_cells += 1
292
+ while ((parsed_cells < cells) and (parsed_cells != src_size))
293
+ generate_separator(:DT_COLSEP, out_dev, fs, rs)
294
+ generate_body(src[parsed_cells], out_dev, fs, rs)
295
+ parsed_cells += 1
296
+ end
297
+ if (parsed_cells == cells)
298
+ generate_separator(:DT_ROWSEP, out_dev, fs, rs)
299
+ else
300
+ generate_separator(:DT_COLSEP, out_dev, fs, rs)
301
+ end
302
+ parsed_cells
303
+ end
304
+
305
+ # Private class methods.
306
+ class << self
307
+ private
308
+
309
+ def open_reader(path, mode, fs, rs, &block)
310
+ file = File.open(path, mode)
311
+ if block
312
+ begin
313
+ CSV::Reader.parse(file, fs, rs) do |row|
314
+ yield(row)
315
+ end
316
+ ensure
317
+ file.close
318
+ end
319
+ nil
320
+ else
321
+ reader = CSV::Reader.create(file, fs, rs)
322
+ reader.close_on_terminate
323
+ reader
324
+ end
325
+ end
326
+
327
+ def open_writer(path, mode, fs, rs, &block)
328
+ file = File.open(path, mode)
329
+ if block
330
+ begin
331
+ CSV::Writer.generate(file, fs, rs) do |writer|
332
+ yield(writer)
333
+ end
334
+ ensure
335
+ file.close
336
+ end
337
+ nil
338
+ else
339
+ writer = CSV::Writer.create(file, fs, rs)
340
+ writer.close_on_terminate
341
+ writer
342
+ end
343
+ end
344
+
345
+ def parse_body(src, idx, fs, rs)
346
+ fs_str = fs
347
+ fs_size = fs_str.size
348
+ rs_str = rs || "\n"
349
+ rs_size = rs_str.size
350
+ fs_idx = rs_idx = 0
351
+ cell = Cell.new
352
+ state = :ST_START
353
+ quoted = cr = false
354
+ c = nil
355
+ last_idx = idx
356
+ while c = src[idx]
357
+ unless quoted
358
+ fschar = (c == fs_str[fs_idx])
359
+ rschar = (c == rs_str[rs_idx])
360
+ # simple 1 char backtrack
361
+ if !fschar and c == fs_str[0]
362
+ fs_idx = 0
363
+ fschar = true
364
+ if state == :ST_START
365
+ state = :ST_DATA
366
+ elsif state == :ST_QUOTE
367
+ raise IllegalFormatError
368
+ end
369
+ end
370
+ if !rschar and c == rs_str[0]
371
+ rs_idx = 0
372
+ rschar = true
373
+ if state == :ST_START
374
+ state = :ST_DATA
375
+ elsif state == :ST_QUOTE
376
+ raise IllegalFormatError
377
+ end
378
+ end
379
+ end
380
+ if c == ?"
381
+ fs_idx = rs_idx = 0
382
+ if cr
383
+ raise IllegalFormatError
384
+ end
385
+ cell << src[last_idx, (idx - last_idx)]
386
+ last_idx = idx
387
+ if state == :ST_DATA
388
+ if quoted
389
+ last_idx += 1
390
+ quoted = false
391
+ state = :ST_QUOTE
392
+ else
393
+ raise IllegalFormatError
394
+ end
395
+ elsif state == :ST_QUOTE
396
+ cell << c.chr
397
+ last_idx += 1
398
+ quoted = true
399
+ state = :ST_DATA
400
+ else # :ST_START
401
+ quoted = true
402
+ last_idx += 1
403
+ state = :ST_DATA
404
+ end
405
+ elsif fschar or rschar
406
+ if fschar
407
+ fs_idx += 1
408
+ end
409
+ if rschar
410
+ rs_idx += 1
411
+ end
412
+ sep = nil
413
+ if fs_idx == fs_size
414
+ if state == :ST_START and rs_idx > 0 and fs_idx < rs_idx
415
+ state = :ST_DATA
416
+ end
417
+ cell << src[last_idx, (idx - last_idx - (fs_size - 1))]
418
+ last_idx = idx
419
+ fs_idx = rs_idx = 0
420
+ if cr
421
+ raise IllegalFormatError
422
+ end
423
+ sep = :DT_COLSEP
424
+ elsif rs_idx == rs_size
425
+ if state == :ST_START and fs_idx > 0 and rs_idx < fs_idx
426
+ state = :ST_DATA
427
+ end
428
+ if !(rs.nil? and cr)
429
+ cell << src[last_idx, (idx - last_idx - (rs_size - 1))]
430
+ last_idx = idx
431
+ end
432
+ fs_idx = rs_idx = 0
433
+ sep = :DT_ROWSEP
434
+ end
435
+ if sep
436
+ if state == :ST_DATA
437
+ return sep, idx + 1, cell;
438
+ elsif state == :ST_QUOTE
439
+ return sep, idx + 1, cell;
440
+ else # :ST_START
441
+ return sep, idx + 1, nil
442
+ end
443
+ end
444
+ elsif rs.nil? and c == ?\r
445
+ # special \r treatment for backward compatibility
446
+ fs_idx = rs_idx = 0
447
+ if cr
448
+ raise IllegalFormatError
449
+ end
450
+ cell << src[last_idx, (idx - last_idx)]
451
+ last_idx = idx
452
+ if quoted
453
+ state = :ST_DATA
454
+ else
455
+ cr = true
456
+ end
457
+ else
458
+ fs_idx = rs_idx = 0
459
+ if state == :ST_DATA or state == :ST_START
460
+ if cr
461
+ raise IllegalFormatError
462
+ end
463
+ state = :ST_DATA
464
+ else # :ST_QUOTE
465
+ raise IllegalFormatError
466
+ end
467
+ end
468
+ idx += 1
469
+ end
470
+ if state == :ST_START
471
+ if fs_idx > 0 or rs_idx > 0
472
+ state = :ST_DATA
473
+ else
474
+ return :DT_EOS, idx, nil
475
+ end
476
+ elsif quoted
477
+ raise IllegalFormatError
478
+ elsif cr
479
+ raise IllegalFormatError
480
+ end
481
+ cell << src[last_idx, (idx - last_idx)]
482
+ last_idx = idx
483
+ return :DT_EOS, idx, cell
484
+ end
485
+
486
+ def generate_body(cell, out_dev, fs, rs)
487
+ if cell.nil?
488
+ # empty
489
+ else
490
+ cell = cell.to_s
491
+ row_data = cell.dup
492
+ # Masaki Ozawa
493
+ if (#row_data.gsub!('"', '""') or
494
+ row_data.index(fs) or
495
+ (rs and row_data.index(rs)) or
496
+ (/[\r\n]/ =~ row_data) or
497
+ (cell.empty?))
498
+ out_dev << '"' << row_data << '"'
499
+ else
500
+ out_dev << row_data
501
+ end
502
+ end
503
+ end
504
+
505
+ def generate_separator(type, out_dev, fs, rs)
506
+ case type
507
+ when :DT_COLSEP
508
+ out_dev << fs
509
+ when :DT_ROWSEP
510
+ out_dev << (rs || "\n")
511
+ end
512
+ end
513
+ end
514
+
515
+
516
+ # CSV formatted string/stream reader.
517
+ #
518
+ # EXAMPLE
519
+ # read CSV lines untill the first column is 'stop'.
520
+ #
521
+ # CSV::Reader.parse(File.open('bigdata', 'rb')) do |row|
522
+ # p row
523
+ # break if !row[0].is_null && row[0].data == 'stop'
524
+ # end
525
+ #
526
+ class Reader
527
+ include Enumerable
528
+
529
+ # Parse CSV data and get lines. Given block is called for each parsed row.
530
+ # Block value is always nil. Rows are not cached for performance reason.
531
+ def Reader.parse(str_or_readable, fs = ',', rs = nil, &block)
532
+ reader = Reader.create(str_or_readable, fs, rs)
533
+ if block
534
+ reader.each do |row|
535
+ yield(row)
536
+ end
537
+ reader.close
538
+ nil
539
+ else
540
+ reader
541
+ end
542
+ end
543
+
544
+ # Returns reader instance.
545
+ def Reader.create(str_or_readable, fs = ',', rs = nil)
546
+ case str_or_readable
547
+ when IO
548
+ IOReader.new(str_or_readable, fs, rs)
549
+ when String
550
+ StringReader.new(str_or_readable, fs, rs)
551
+ else
552
+ IOReader.new(str_or_readable, fs, rs)
553
+ end
554
+ end
555
+
556
+ def each
557
+ while true
558
+ row = []
559
+ parsed_cells = get_row(row)
560
+ if parsed_cells == 0
561
+ break
562
+ end
563
+ yield(row)
564
+ end
565
+ nil
566
+ end
567
+
568
+ def shift
569
+ row = []
570
+ parsed_cells = get_row(row)
571
+ row
572
+ end
573
+
574
+ def close
575
+ terminate
576
+ end
577
+
578
+ private
579
+
580
+ def initialize(dev)
581
+ raise RuntimeError.new('Do not instanciate this class directly.')
582
+ end
583
+
584
+ def get_row(row)
585
+ raise NotImplementedError.new('Method get_row must be defined in a derived class.')
586
+ end
587
+
588
+ def terminate
589
+ # Define if needed.
590
+ end
591
+ end
592
+
593
+
594
+ class StringReader < Reader
595
+ def initialize(string, fs = ',', rs = nil)
596
+ @fs = fs
597
+ @rs = rs
598
+ @dev = string
599
+ @idx = 0
600
+ if @dev[0, 3] == "\xef\xbb\xbf"
601
+ @idx += 3
602
+ end
603
+ end
604
+
605
+ private
606
+
607
+ def get_row(row)
608
+ parsed_cells, next_idx = CSV.parse_row(@dev, @idx, row, @fs, @rs)
609
+ if parsed_cells == 0 and next_idx == 0 and @idx != @dev.size
610
+ raise IllegalFormatError.new
611
+ end
612
+ @idx = next_idx
613
+ parsed_cells
614
+ end
615
+ end
616
+
617
+
618
+ class IOReader < Reader
619
+ def initialize(io, fs = ',', rs = nil)
620
+ @io = io
621
+ @fs = fs
622
+ @rs = rs
623
+ @dev = CSV::IOBuf.new(@io)
624
+ @idx = 0
625
+ if @dev[0] == 0xef and @dev[1] == 0xbb and @dev[2] == 0xbf
626
+ @idx += 3
627
+ end
628
+ @close_on_terminate = false
629
+ end
630
+
631
+ # Tell this reader to close the IO when terminated (Triggered by invoking
632
+ # CSV::IOReader#close).
633
+ def close_on_terminate
634
+ @close_on_terminate = true
635
+ end
636
+
637
+ private
638
+
639
+ def get_row(row)
640
+ parsed_cells, next_idx = CSV.parse_row(@dev, @idx, row, @fs, @rs)
641
+ if parsed_cells == 0 and next_idx == 0 and !@dev.is_eos?
642
+ raise IllegalFormatError.new
643
+ end
644
+ dropped = @dev.drop(next_idx)
645
+ @idx = next_idx - dropped
646
+ parsed_cells
647
+ end
648
+
649
+ def terminate
650
+ if @close_on_terminate
651
+ @io.close
652
+ end
653
+
654
+ if @dev
655
+ @dev.close
656
+ end
657
+ end
658
+ end
659
+
660
+
661
+ # CSV formatted string/stream writer.
662
+ #
663
+ # EXAMPLE
664
+ # Write rows to 'csvout' file.
665
+ #
666
+ # outfile = File.open('csvout', 'wb')
667
+ # CSV::Writer.generate(outfile) do |csv|
668
+ # csv << ['c1', nil, '', '"', "\r\n", 'c2']
669
+ # ...
670
+ # end
671
+ #
672
+ # outfile.close
673
+ #
674
+ class Writer
675
+ # Given block is called with the writer instance. str_or_writable must
676
+ # handle '<<(string)'.
677
+ def Writer.generate(str_or_writable, fs = ',', rs = nil, &block)
678
+ writer = Writer.create(str_or_writable, fs, rs)
679
+ if block
680
+ yield(writer)
681
+ writer.close
682
+ nil
683
+ else
684
+ writer
685
+ end
686
+ end
687
+
688
+ # str_or_writable must handle '<<(string)'.
689
+ def Writer.create(str_or_writable, fs = ',', rs = nil)
690
+ BasicWriter.new(str_or_writable, fs, rs)
691
+ end
692
+
693
+ # dump CSV stream to the device. argument must be an Array of String.
694
+ def <<(row)
695
+ CSV.generate_row(row, row.size, @dev, @fs, @rs)
696
+ self
697
+ end
698
+ alias add_row <<
699
+
700
+ def close
701
+ terminate
702
+ end
703
+
704
+ private
705
+
706
+ def initialize(dev)
707
+ raise RuntimeError.new('Do not instanciate this class directly.')
708
+ end
709
+
710
+ def terminate
711
+ # Define if needed.
712
+ end
713
+ end
714
+
715
+
716
+ class BasicWriter < Writer
717
+ def initialize(str_or_writable, fs = ',', rs = nil)
718
+ @fs = fs
719
+ @rs = rs
720
+ @dev = str_or_writable
721
+ @close_on_terminate = false
722
+ end
723
+
724
+ # Tell this writer to close the IO when terminated (Triggered by invoking
725
+ # CSV::BasicWriter#close).
726
+ def close_on_terminate
727
+ @close_on_terminate = true
728
+ end
729
+
730
+ private
731
+
732
+ def terminate
733
+ if @close_on_terminate
734
+ @dev.close
735
+ end
736
+ end
737
+ end
738
+
739
+ private
740
+
741
+ # Buffered stream.
742
+ #
743
+ # EXAMPLE 1 -- an IO.
744
+ # class MyBuf < StreamBuf
745
+ # # Do initialize myself before a super class. Super class might call my
746
+ # # method 'read'. (Could be awful for C++ user. :-)
747
+ # def initialize(s)
748
+ # @s = s
749
+ # super()
750
+ # end
751
+ #
752
+ # # define my own 'read' method.
753
+ # # CAUTION: Returning nil means EnfOfStream.
754
+ # def read(size)
755
+ # @s.read(size)
756
+ # end
757
+ #
758
+ # # release buffers. in Ruby which has GC, you do not have to call this...
759
+ # def terminate
760
+ # @s = nil
761
+ # super()
762
+ # end
763
+ # end
764
+ #
765
+ # buf = MyBuf.new(STDIN)
766
+ # my_str = ''
767
+ # p buf[0, 0] # => '' (null string)
768
+ # p buf[0] # => 97 (char code of 'a')
769
+ # p buf[0, 1] # => 'a'
770
+ # my_str = buf[0, 5]
771
+ # p my_str # => 'abcde' (5 chars)
772
+ # p buf[0, 6] # => "abcde\n" (6 chars)
773
+ # p buf[0, 7] # => "abcde\n" (6 chars)
774
+ # p buf.drop(3) # => 3 (dropped chars)
775
+ # p buf.get(0, 2) # => 'de' (2 chars)
776
+ # p buf.is_eos? # => false (is not EOS here)
777
+ # p buf.drop(5) # => 3 (dropped chars)
778
+ # p buf.is_eos? # => true (is EOS here)
779
+ # p buf[0] # => nil (is EOS here)
780
+ #
781
+ # EXAMPLE 2 -- String.
782
+ # This is a conceptual example. No pros with this.
783
+ #
784
+ # class StrBuf < StreamBuf
785
+ # def initialize(s)
786
+ # @str = s
787
+ # @idx = 0
788
+ # super()
789
+ # end
790
+ #
791
+ # def read(size)
792
+ # str = @str[@idx, size]
793
+ # @idx += str.size
794
+ # str
795
+ # end
796
+ # end
797
+ #
798
+ class StreamBuf
799
+ # get a char or a partial string from the stream.
800
+ # idx: index of a string to specify a start point of a string to get.
801
+ # unlike String instance, idx < 0 returns nil.
802
+ # n: size of a string to get.
803
+ # returns char at idx if n == nil.
804
+ # returns a partial string, from idx to (idx + n) if n != nil. at EOF,
805
+ # the string size could not equal to arg n.
806
+ def [](idx, n = nil)
807
+ if idx < 0
808
+ return nil
809
+ end
810
+ if (idx_is_eos?(idx))
811
+ if n and (@offset + idx == buf_size(@cur_buf))
812
+ # Like a String, 'abc'[4, 1] returns nil and
813
+ # 'abc'[3, 1] returns '' not nil.
814
+ return ''
815
+ else
816
+ return nil
817
+ end
818
+ end
819
+ my_buf = @cur_buf
820
+ my_offset = @offset
821
+ next_idx = idx
822
+ while (my_offset + next_idx >= buf_size(my_buf))
823
+ if (my_buf == @buf_tail_idx)
824
+ unless add_buf
825
+ break
826
+ end
827
+ end
828
+ next_idx = my_offset + next_idx - buf_size(my_buf)
829
+ my_buf += 1
830
+ my_offset = 0
831
+ end
832
+ loc = my_offset + next_idx
833
+ if !n
834
+ return @buf_list[my_buf][loc] # Fixnum of char code.
835
+ elsif (loc + n - 1 < buf_size(my_buf))
836
+ return @buf_list[my_buf][loc, n] # String.
837
+ else # should do loop insted of (tail) recursive call...
838
+ res = @buf_list[my_buf][loc, BufSize]
839
+ size_added = buf_size(my_buf) - loc
840
+ if size_added > 0
841
+ idx += size_added
842
+ n -= size_added
843
+ ret = self[idx, n]
844
+ if ret
845
+ res << ret
846
+ end
847
+ end
848
+ return res
849
+ end
850
+ end
851
+ alias get []
852
+
853
+ # drop a string from the stream.
854
+ # returns dropped size. at EOF, dropped size might not equals to arg n.
855
+ # Once you drop the head of the stream, access to the dropped part via []
856
+ # or get returns nil.
857
+ def drop(n)
858
+ if is_eos?
859
+ return 0
860
+ end
861
+ size_dropped = 0
862
+ while (n > 0)
863
+ if !@is_eos or (@cur_buf != @buf_tail_idx)
864
+ if (@offset + n < buf_size(@cur_buf))
865
+ size_dropped += n
866
+ @offset += n
867
+ n = 0
868
+ else
869
+ size = buf_size(@cur_buf) - @offset
870
+ size_dropped += size
871
+ n -= size
872
+ @offset = 0
873
+ unless rel_buf
874
+ unless add_buf
875
+ break
876
+ end
877
+ @cur_buf = @buf_tail_idx
878
+ end
879
+ end
880
+ end
881
+ end
882
+ size_dropped
883
+ end
884
+
885
+ def is_eos?
886
+ return idx_is_eos?(0)
887
+ end
888
+
889
+ # WARN: Do not instantiate this class directly. Define your own class
890
+ # which derives this class and define 'read' instance method.
891
+ def initialize
892
+ @buf_list = []
893
+ @cur_buf = @buf_tail_idx = -1
894
+ @offset = 0
895
+ @is_eos = false
896
+ add_buf
897
+ @cur_buf = @buf_tail_idx
898
+ end
899
+
900
+ protected
901
+
902
+ def terminate
903
+ while (rel_buf); end
904
+ end
905
+
906
+ # protected method 'read' must be defined in derived classes.
907
+ # CAUTION: Returning a string which size is not equal to 'size' means
908
+ # EnfOfStream. When it is not at EOS, you must block the callee, try to
909
+ # read and return the sized string.
910
+ def read(size) # raise EOFError
911
+ raise NotImplementedError.new('Method read must be defined in a derived class.')
912
+ end
913
+
914
+ private
915
+
916
+ def buf_size(idx)
917
+ @buf_list[idx].size
918
+ end
919
+
920
+ def add_buf
921
+ if @is_eos
922
+ return false
923
+ end
924
+ begin
925
+ str_read = read(BufSize)
926
+ rescue EOFError
927
+ str_read = nil
928
+ rescue
929
+ terminate
930
+ raise
931
+ end
932
+ if str_read.nil?
933
+ @is_eos = true
934
+ @buf_list.push('')
935
+ @buf_tail_idx += 1
936
+ false
937
+ else
938
+ @buf_list.push(str_read)
939
+ @buf_tail_idx += 1
940
+ true
941
+ end
942
+ end
943
+
944
+ def rel_buf
945
+ if (@cur_buf < 0)
946
+ return false
947
+ end
948
+ @buf_list[@cur_buf] = nil
949
+ if (@cur_buf == @buf_tail_idx)
950
+ @cur_buf = -1
951
+ return false
952
+ else
953
+ @cur_buf += 1
954
+ return true
955
+ end
956
+ end
957
+
958
+ def idx_is_eos?(idx)
959
+ (@is_eos and ((@cur_buf < 0) or (@cur_buf == @buf_tail_idx)))
960
+ end
961
+
962
+ BufSize = 1024 * 8
963
+ end
964
+
965
+ # Buffered IO.
966
+ #
967
+ # EXAMPLE
968
+ # # File 'bigdata' could be a giga-byte size one!
969
+ # buf = CSV::IOBuf.new(File.open('bigdata', 'rb'))
970
+ # CSV::Reader.new(buf).each do |row|
971
+ # p row
972
+ # break if row[0].data == 'admin'
973
+ # end
974
+ #
975
+ class IOBuf < StreamBuf
976
+ def initialize(s)
977
+ @s = s
978
+ super()
979
+ end
980
+
981
+ def close
982
+ terminate
983
+ end
984
+
985
+ private
986
+
987
+ def read(size)
988
+ @s.read(size)
989
+ end
990
+
991
+ def terminate
992
+ super()
993
+ end
994
+ end
995
+ end
996
+
997
+