syclink 0.0.2 → 0.1.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: e589b7afc92a5b81224d34df04f9aa8de84d4e66
4
- data.tar.gz: e50dbfae41eef5d476fb3e9c95b8505401d49c4a
3
+ metadata.gz: 757f2615ff72bd3c25ef404172faa9308e2a0c7f
4
+ data.tar.gz: a0a0ccac857393f6a4beae8a50a0f356e5faf578
5
5
  SHA512:
6
- metadata.gz: 7cdd7ddbcd51e14acacb585bdbfe4f6760c970d63de348200194d5fd222ebe78e6a816d59bdea44db064119ee879f0354b7656099be74f3bfdaedf0a4f78e548
7
- data.tar.gz: 4fd0b2f5036a5884a8cb8fdd3991d6058c044e04b828957aa89b43ea594c68bdd3823fa31a65d9b4a15f98756e6fc22a99e9f210bec092ae3e3c21a63205586c
6
+ metadata.gz: 737469dcc6463c9e13dc21b8cc310c93206bdd18f3a8a9a6ecaf5e164930a48291c4d42ecab3bbee81cc0e7a854cb6a66e27034cf73d14df068b4a16eb9ab48f
7
+ data.tar.gz: 0dadc454dcba9d28a8b4123a680a109dc860b216274e3800ce6c94259b3f088f3b86e1f6a3e36fb415a8980f2248568b0fbc6607cbdb6af119aaa69a3cd74fe5
data/Gemfile.lock CHANGED
@@ -1,8 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- syclink (0.0.1)
4
+ syclink (0.0.2)
5
5
  gli (= 2.13.1)
6
+ sqlite3 (= 1.3.10)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -23,11 +24,12 @@ GEM
23
24
  rspec-support (~> 3.3.0)
24
25
  rspec-support (3.3.0)
25
26
  sass (3.4.15)
27
+ sqlite3 (1.3.10)
26
28
 
27
29
  PLATFORMS
28
30
  ruby
29
31
 
30
32
  DEPENDENCIES
31
- rspec
32
- sass
33
+ rspec (= 3.3.0)
34
+ sass (= 3.4.15)
33
35
  syclink!
data/README.md CHANGED
@@ -27,14 +27,29 @@ _Website commands_
27
27
  * website show - show all websites or search for websites
28
28
  * website remove - Remove website
29
29
  * website create - Create a HTML representation of the website
30
+ * website check - Check from links that are not active anymore (pending)
31
+ * website edit - Open the YAML file for editing (pending)
30
32
 
31
33
  _Link commands_
32
- * add - Add a link
33
- * file - Add links from a file
34
- * update - Update a link
35
- * delete - Delete a link
36
- * list - List all links with an optional filter
37
- * find - Find links based on a search string
34
+ * add link - Add a link
35
+ * add file - Add links from a file
36
+ * update link - Update a link
37
+ * update file - Update links saved to a file
38
+ * delete - Delete one or more links
39
+ * list - List all links with an optional filter
40
+ * find - Find links based on a search string
41
+ * merge - Merge multiple links with same URL
42
+
43
+ _Import commands_
44
+ * import mf - Import Mozilla Firefox bookmarks
45
+ * import gc - Import Google Chrome bookmarks
46
+ * import ie - Import Internet Explorer bookmarks
47
+ * import dir - Import links to files from a directory
48
+
49
+ _Export commands_
50
+ * export xml - Export links in XML fromat (pending)
51
+ * export json - Export links in JSON format (pending)
52
+ * export csv - Export links in csv format
38
53
 
39
54
  Commands
40
55
  ========
@@ -189,3 +204,66 @@ Following is showing the above sequence in commands
189
204
  $ syclink add "http://github.com" --tag DEVELOPMENT
190
205
  $ syclink website create
191
206
 
207
+ Importing Bookmarks from Webrowsers
208
+ ===================================
209
+
210
+ Firefox
211
+ -------
212
+ The bookmarks of _Firefox_ are located in the user's home folder in
213
+ `~/.mozilla/SOME_CRYPTIC_NAME.default/places.sqlite`.
214
+
215
+ The database can be explored with _sqlite3_ from the command line
216
+
217
+ $ cd ~/.mozilla/SOME_CRYPTIC_NAME.default/
218
+ $ sqlite3 places.sqlite
219
+ >
220
+
221
+ We want to retrieve url, title, description, tag, key and bookmark. tag, key
222
+ and bookmark are good candidates for tags for the application.
223
+
224
+ At the command prompt of SQLite3 We can issue the query
225
+
226
+ ````
227
+ sqlite> select p.id, p.url, p.title, b.id, b.fk, b.parent, b.title,
228
+ ...> k.keyword, a.content, b_t.title from moz_bookmarks b
229
+ ...> left outer join moz_keywords k on b.keyword_id = k.id
230
+ ...> left outer join moz_items_annos a on a.item_id = b.id
231
+ ...> left outer join moz_bookmarks b_t on b.parent = b_t.id
232
+ ...> join moz_places p on p.id = b.fk where p.url like "http%";
233
+ 1|https://www.mozilla.org/en-US/firefox/central/||6|1|3|Getting Started|||\
234
+ Bookmarks Toolbar
235
+ 2|http://www.ubuntu.com/||8|2|7|Ubuntu|||Ubuntu and Free Software links
236
+ 3|http://wiki.ubuntu.com/||9|3|7|Ubuntu Wiki (community-edited website)|||\
237
+ Ubuntu and Free Software links
238
+ 4|https://answers.launchpad.net/ubuntu/+addquestion||10|4|7|Make a Support \
239
+ Request to the Ubuntu Community|||Ubuntu and Free Software links
240
+ 5|http://www.debian.org/||11|5|7|Debian (Ubuntu is based on Debian)|||Ubuntu \
241
+ and Free Software links
242
+ 6|https://one.ubuntu.com/||12|6|7|Ubuntu One - The personal cloud that brings\
243
+ your digital life together|||Ubuntu and Free Software links
244
+ 7|https://www.mozilla.org/en-US/firefox/help/||14|7|13|Help and Tutorials|||\
245
+ Mozilla Firefox
246
+ 8|https://www.mozilla.org/en-US/firefox/customize/||15|8|13|Customize \
247
+ Firefox|||Mozilla Firefox
248
+ 9|https://www.mozilla.org/en-US/contribute/||16|9|13|Get Involved|||Mozilla \
249
+ Firefox
250
+ 10|https://www.mozilla.org/en-US/about/||17|10|13|About Us|||Mozilla Firefox
251
+ 4717|http://codekata.com/|CodeKata|30|4717|5|CodeKata|liklo|How do you get \
252
+ to be a great musician? It helps to know the theory,
253
+ and to understand the mechanics of your instrument. It helps to have
254
+ talent. But …|Unsorted Bookmarks
255
+ 399|http://localhost:3000/|Secondhand | Home|34|399|2|Secondhand | Home|||\
256
+ Bookmarks Menu
257
+ 12870|https://www.sqlite.org/cli.html|Command Line Shell For SQLite|35|12870|\
258
+ 5|Command Line Shell For SQLite|dark|What is this sqlite all about?|Unsorted \
259
+ Bookmarks
260
+ 4717|http://codekata.com/|CodeKata|37|4717|36||||wenga
261
+ 12870|https://www.sqlite.org/cli.html|Command Line Shell For SQLite|39|12870|\
262
+ 38||||lite
263
+ 12883|http://ruby.bastardsbook.com/chapters/sql/#h-2-5|SQL | The Bastards \
264
+ Book of Ruby|40|12883|5|SQL | The Bastards Book of Ruby|||Unsorted Bookmarks
265
+ 12883|http://ruby.bastardsbook.com/chapters/sql/#h-2-5|SQL | The Bastards \
266
+ Book of Ruby|42|12883|41||||Ruby
267
+ sqlite>
268
+ ````
269
+
data/bin/syclink CHANGED
@@ -14,7 +14,8 @@ include SycLink::Infrastructure
14
14
  include SycLink::Formatter
15
15
 
16
16
  # Commands that need to have a website and a designer object
17
- WEBSITE_COMMANDS = [ :create, :add, :file, :update, :delete, :list, :find ]
17
+ WEBSITE_COMMANDS = [ :create, :link, :file, :update, :delete, :list, :find,
18
+ :dir, :mf, :gc, :ie, :csv, :merge ]
18
19
 
19
20
  # syclink's configuration directory
20
21
  syclink_directory = File.expand_path("~/.syc/syclink")
@@ -54,7 +55,7 @@ copy_file_if_missing(File.join(File.dirname(__FILE__),
54
55
 
55
56
  config = load_config(syclink_file)
56
57
 
57
- program_desc 'Create a link list and display it as an html page'
58
+ program_desc 'Create a link-list and display it as an html page'
58
59
 
59
60
  version SycLink::VERSION
60
61
 
@@ -65,63 +66,89 @@ desc 'Website to operate on'
65
66
  arg_name 'WEBSITE'
66
67
  flag [:w,:website]
67
68
 
68
- desc 'Add a link to the website'
69
- arg_name 'URL'
69
+ desc 'Add a link from command line or links from a file to the website'
70
70
  command :add do |c|
71
71
 
72
- c.desc 'Name of the link'
73
- c.arg_name 'NAME'
74
- c.flag [:n, :name]
72
+ c.desc 'Add a link from the command line to the website'
73
+ c.arg_name 'URL'
74
+ c.command :link do |s|
75
+ s.desc 'Name of the link'
76
+ s.arg_name 'NAME'
77
+ s.flag [:n, :name]
75
78
 
76
- c.desc 'Description of the link'
77
- c.arg_name 'DESCRIPTION'
78
- c.flag [:d, :description]
79
+ s.desc 'Description of the link'
80
+ s.arg_name 'DESCRIPTION'
81
+ s.flag [:d, :description]
79
82
 
80
- c.desc 'Tag the link is associated to'
81
- c.arg_name 'TAG'
82
- c.flag [:t, :tag]
83
+ s.desc 'Tag the link is associated to'
84
+ s.arg_name 'TAG'
85
+ s.flag [:t, :tag]
83
86
 
84
- c.action do |global_options,options,args|
87
+ s.action do |global_options,options,args|
85
88
 
86
- @designer.add_link(args[0], options)
89
+ @designer.add_link(args[0], options)
87
90
 
91
+ end
88
92
  end
89
- end
90
93
 
91
- desc 'Add links from a file to the website'
92
- arg_name 'FILE'
93
- command :file do |c|
94
+ c.desc 'Add links from a file to the website'
95
+ c.arg_name 'FILE'
96
+ c.command :file do |s|
94
97
 
95
- c.action do |global_options,options,args|
98
+ s.action do |global_options,options,args|
96
99
 
97
- @designer.add_links_from_file(args[0])
100
+ @designer.add_links_from_file(args[0])
98
101
 
102
+ end
99
103
  end
100
104
  end
101
105
 
102
- desc 'Update a link'
103
- arg_name 'URL'
106
+ desc 'Update a link from command line or links from file'
104
107
  command :update do |c|
105
108
 
106
- c.desc 'Name of the link'
107
- c.arg_name 'NAME'
108
- c.flag [:n, :name]
109
+ c.desc 'Update a link from the command line'
110
+ c.arg_name 'URL'
111
+ c.command :link do |s|
109
112
 
110
- c.desc 'Description of the link'
111
- c.arg_name 'DESCRIPTION'
112
- c.flag [:d, :description]
113
+ s.desc 'Name of the link'
114
+ s.arg_name 'NAME'
115
+ s.flag [:n, :name]
113
116
 
114
- c.desc 'Tag the link is associated to'
115
- c.arg_name 'TAG'
116
- c.flag [:t, :tag]
117
+ s.desc 'Description of the link'
118
+ s.arg_name 'DESCRIPTION'
119
+ s.flag [:d, :description]
117
120
 
118
- c.action do |global_options,options,args|
121
+ s.desc 'Tag the link is associated to'
122
+ s.arg_name 'TAG'
123
+ s.flag [:t, :tag]
124
+
125
+ s.action do |global_options,options,args|
119
126
 
120
- @designer.update_link(args[0], options)
127
+ @designer.update_link(args[0], options)
128
+
129
+ end
130
+ end
131
+
132
+ c.desc "Update links by reading from file"
133
+ c.arg_name 'FILE'
134
+ c.command :file do |s|
135
+
136
+ s.action do |global_options,options,args|
137
+
138
+ @designer.update_links_from_file(args[0])
139
+
140
+ end
121
141
 
122
142
  end
123
143
  end
124
144
 
145
+ desc 'Merge links with same URL'
146
+ command :merge do |c|
147
+ c.action do |global_options,options,args|
148
+ @designer.merge_links
149
+ end
150
+ end
151
+
125
152
  desc 'Find a link'
126
153
  arg_name 'FIND_STRING'
127
154
  command :find do |c|
@@ -131,17 +158,31 @@ command :find do |c|
131
158
  c.arg_name 'URL, NAME, DESCRIPTION, TAG'
132
159
  c.flag [:c, :columns]
133
160
 
161
+ c.desc 'Table width'
162
+ c.arg_name 'WIDTH'
163
+ c.flag [:w, :width], :type => Integer
164
+
165
+ c.desc 'Expand table to full width of specified WIDTH'
166
+ c.default_value true
167
+ c.switch [:e, :expand]
168
+
134
169
  c.action do |global_options,options,args|
135
170
 
136
- print_links(@designer.find_links(args[0].downcase), options[:c])
171
+ if args[0].nil?
172
+ STDERR.puts "Warning: You need to specify a FIND_STRING"
173
+ STDERR.puts "If you want to list all links use 'syclink list'"
174
+ else
175
+ print_links(@designer.find_links(args[0]), options[:c], options)
176
+ end
137
177
 
138
178
  end
139
179
  end
140
180
 
141
181
  desc 'Remove one or more links'
142
- arg_name 'URL[URL,URL]'
182
+ arg_name 'URL [URL URL]'
143
183
  command :delete do |c|
144
184
  c.action do |global_options,options,args|
185
+ p args
145
186
  @designer.remove_links(args)
146
187
  end
147
188
  end
@@ -170,9 +211,17 @@ command :list do |c|
170
211
  c.arg_name 'URL, NAME, DESCRIPTION, TAG'
171
212
  c.flag [:c, :columns]
172
213
 
214
+ c.desc 'Table width'
215
+ c.arg_name 'WIDTH'
216
+ c.flag [:w, :width], :type => Integer
217
+
218
+ c.desc 'Expand table to full width of specified WIDTH'
219
+ c.default_value true
220
+ c.switch [:e, :expand]
221
+
173
222
  c.action do |global_options,options,args|
174
223
 
175
- print_links(@designer.list_links(options), options[:c])
224
+ print_links(@designer.list_links(options), options[:c], options)
176
225
 
177
226
  end
178
227
  end
@@ -232,6 +281,107 @@ command :website do |c|
232
281
  c.default_command :create
233
282
  end
234
283
 
284
+ desc "Import links from Firefox, Chrome, Internet Explorer or directory"
285
+ command :import do |c|
286
+
287
+ c.desc 'Import links from Mozilla Firefox'
288
+ c.arg_name 'PATH_TO_FIREFOX_DATABASE'
289
+ c.command :mf do |s|
290
+
291
+ s.action do |global_options,options,args|
292
+ unless File.exists? args[0]
293
+ STDERR.puts <<-HERE.gsub(/^ {10}/, '')
294
+ Error: #{args[0]} doesn't exist!
295
+ Firefox stores its bookmarks in a SQLite3 database called
296
+ places.sqlite. With Ubuntu this database is usually located in
297
+ '~/.mozilla/firefox/*.default/places.sqlite'.
298
+ If you are on Windows
299
+ the file is located in the user's home directory
300
+ '~/AppData/Roaming/Mozilla/Profiles/*.default/places.sqlite'.
301
+ HERE
302
+ exit(0)
303
+ else
304
+ @designer.import_links(SycLink::Firefox.new(args.shift))
305
+ end
306
+ end
307
+ end
308
+
309
+ c.desc 'Import links from Google Chrome'
310
+ c.arg_name 'PATH_TO_CHROME_BOOKMARKS'
311
+ c.command :gc do |s|
312
+
313
+ s.action do |global_options,options,args|
314
+ unless File.exists? args[0]
315
+ STDERR.puts <<-HERE.gsub(/^ {10}/, '')
316
+ Error: #{args[0]} doesn't exist!
317
+ Google Chrome stores its bookmarks in a JSON file called
318
+ Bookmarks. With Ubuntu this file is usually located in
319
+ '~/.config/chromium/Default/Bookmarks'.
320
+ If you are on Windows
321
+ the file is located in the user's home directory
322
+ '~/AppData/Local/Google/Chrome/User Data/Bookmarks'.
323
+ HERE
324
+ exit(0)
325
+ else
326
+ @designer.import_links(SycLink::Chrome.new(args.shift))
327
+ end
328
+ end
329
+ end
330
+
331
+ c.desc 'Import links from Internet Explorer'
332
+ c.arg_name 'PATH_TO_INTERNET_EXPLORER_BOOKMARKS'
333
+ c.command :ie do |s|
334
+
335
+ s.action do |global_options,options,args|
336
+ unless File.exists? args[0]
337
+ STDERR.puts <<-HERE.gsub(/^ {10}/, '')
338
+ Error: #{args[0]} doesn't exist!
339
+ Internet Explorer stores its bookmarks in a directory structure.
340
+ the bookmarks are located in the user's home directory
341
+ '~/AppData/Favorites'.
342
+ HERE
343
+ exit(0)
344
+ else
345
+ @designer.import_links(SycLink::InternetExplorer.new(args.shift))
346
+ end
347
+ end
348
+ end
349
+
350
+ c.desc 'Import links from a Directory'
351
+ c.long_desc <<-HERE.gsub(/^ {4}/, '')
352
+ The PATH_TO_DIRECTORY can have patterns that allows to import specific
353
+ files.
354
+
355
+ Examples:
356
+
357
+ PATH_TO_DIRECTORY/**/*.pdf will import all pdf-files in the directories and
358
+ sub-directory
359
+
360
+ PATH_TO_DIRECTORY/**/* will import all files and sub-directories
361
+ HERE
362
+
363
+ c.arg_name 'PATH_TO_DIRECTORY'
364
+ c.command :dir do |s|
365
+
366
+ s.action do |global_options,options,args|
367
+ @designer.import_links(SycLink::FileImporter.new(args.shift))
368
+ end
369
+ end
370
+ end
371
+
372
+ desc 'Export to csv'
373
+ command :export do |c|
374
+
375
+ c.desc 'Export links to csv'
376
+ c.command :csv do |s|
377
+
378
+ s.action do |global_options,options,args|
379
+ puts @designer.export(:csv)
380
+ end
381
+ end
382
+
383
+ end
384
+
235
385
  pre do |global,command,options,args|
236
386
 
237
387
  if WEBSITE_COMMANDS.include?(command.name)
@@ -281,10 +431,10 @@ on_error do |exception|
281
431
  end
282
432
  end
283
433
 
284
- def print_links(links, columns)
434
+ def print_links(links, columns, opts = {})
285
435
  allowed_cols = %w{ url name description tag }
286
436
  cols = columns.delete(' ').downcase.split(',') & allowed_cols
287
- SycLink::Formatter.table(links, cols)
437
+ SycLink::Formatter.table(links, cols, opts)
288
438
  end
289
439
 
290
440
  exit run(ARGV)
@@ -0,0 +1,37 @@
1
+ require "json"
2
+
3
+ # Module that creates a link list and generates an html representation
4
+ module SycLink
5
+
6
+ # Importer for Google Chrome links
7
+ class Chrome < Importer
8
+
9
+ # Reads the content of the Google Chrome bookmarks file
10
+ def read
11
+ serialized = File.read(path)
12
+ extract_links(JSON.parse(serialized)).flatten.each_slice(4).to_a
13
+ end
14
+
15
+ private
16
+
17
+ # Extracts the links from the JSON file
18
+ def extract_links(json)
19
+ json["roots"].collect do |key, children|
20
+ extract_children(children["name"], children["children"])
21
+ end
22
+ end
23
+
24
+ # Extracts the children from the JSON file
25
+ def extract_children(tag, children)
26
+ children.map do |child|
27
+ if child["children"]
28
+ extract_children("#{tag},#{child['name']}", child["children"])
29
+ else
30
+ [child["url"], child["name"], "", tag]
31
+ end
32
+ end
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -29,13 +29,31 @@ module SycLink
29
29
  # are added to the websie
30
30
  def add_links_from_file(file)
31
31
  File.foreach(file) do |line|
32
- url, name, description, tag = line.split(';')
32
+ next if line.chomp.empty?
33
+ url, name, description, tag = line.chomp.split(';')
33
34
  website.add_link(Link.new(url, { name: name,
34
35
  description: description,
35
36
  tag: tag }))
36
37
  end
37
38
  end
38
39
 
40
+ # Accepts and SycLink::Importer to import Links and add them to the website
41
+ def import_links(importer)
42
+ importer.links.each do |link|
43
+ website.add_link(link)
44
+ end
45
+ end
46
+
47
+ # Export links to specified format
48
+ def export(format)
49
+ message = "to_#{format.downcase}"
50
+ if website.respond_to? message
51
+ website.send(message)
52
+ else
53
+ raise "cannot export to #{format}"
54
+ end
55
+ end
56
+
39
57
  # List links contained in the website and optionally filter on attributes
40
58
  def list_links(args = {})
41
59
  website.list_links(args)
@@ -52,6 +70,21 @@ module SycLink
52
70
  website.find_links(url).first.update(args)
53
71
  end
54
72
 
73
+ def update_links_from_file(file)
74
+ File.foreach(file) do |line|
75
+ next if line.chomp.empty?
76
+ url, name, description, tag = line.chomp.split(';')
77
+ website.find_links(url).first.update({ name: name,
78
+ description: description,
79
+ tag: tag })
80
+ end
81
+ end
82
+
83
+ # Merge links with same URL
84
+ def merge_links
85
+ website.merge_links_on(:url)
86
+ end
87
+
55
88
  # Deletes one or more links from the website. Returns the deleted links.
56
89
  # Expects the links provided in an array
57
90
  def remove_links(urls)
@@ -12,6 +12,12 @@ module SycLink
12
12
  renderer.result(binding)
13
13
  end
14
14
 
15
+ # Takes an array of row values and converts them to a csv string. Expects
16
+ # that the importing class is having a method rows.
17
+ def to_csv
18
+ rows.map { |row| row.join(';') }.join("\n")
19
+ end
20
+
15
21
  end
16
22
 
17
23
  end
@@ -0,0 +1,19 @@
1
+ module SycLink
2
+
3
+ class FileImporter < Importer
4
+
5
+ def read
6
+ root_dir = File.dirname(path).scan(/^[^\*|\?]*/).first
7
+ regex = Regexp.new("(?<=#{root_dir}).*")
8
+ Dir.glob(path).map do |file|
9
+ url = file
10
+ name = File.basename(file)
11
+ description = ""
12
+ tags = extract_tags(File.dirname(file).scan(regex))
13
+ [url, name, description, tags]
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,36 @@
1
+ require 'sqlite3'
2
+ require_relative 'importer'
3
+
4
+ # Module that creates a link list and generates an html representation
5
+ module SycLink
6
+
7
+ # Importer for Firefox links
8
+ class Firefox < Importer
9
+
10
+ # Query strig to read links from the Firefox database places.sqlite
11
+ QUERY_STRING = "select p.url, p.title, b.title, a.content, k.keyword, b_t.title from moz_bookmarks b left outer join moz_keywords k on b.keyword_id = k.id left outer join moz_items_annos a on a.item_id = b.id left outer join moz_bookmarks b_t on b.parent = b_t.id join moz_places p on p.id = b.fk where p.url like 'http%';"
12
+
13
+ # Reads the links from the Firefox database places.sqlite
14
+ def read
15
+ bookmark_file = Dir.glob(File.expand_path(path)).shift
16
+ raise "Did not find file #{path}" unless bookmark_file
17
+
18
+ db = SQLite3::Database.new(path)
19
+
20
+ import = db.execute(QUERY_STRING)
21
+ end
22
+
23
+ # Returns row values in Arrays
24
+ def rows
25
+ read.map do |row|
26
+ a = row[0]; b = row[1]; c = row[2]; d = row[3]; e = row[4]; f = row[5]
27
+ [a,
28
+ b || c,
29
+ (d || '').gsub("\n", ' '),
30
+ [e, f].join(',').gsub(/^,|,$/, '')]
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ end