csvyaml 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +6 -0
- data/README.md +4 -3
- data/Rakefile +1 -1
- data/lib/csvyaml.rb +13 -3
- data/lib/csvyaml/parser.rb +133 -0
- data/lib/csvyaml/version.rb +3 -2
- data/test/data/hello.yaml.csv +3 -0
- data/test/data/hello11.yaml.csv +5 -0
- data/test/helper.rb +20 -0
- data/test/test_parser.rb +104 -0
- data/test/test_parser_misc.rb +82 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c07f82dfd13c43d0246141a6c79d36d42222d00a
|
4
|
+
data.tar.gz: 45ac0671f99a0d44b7ffd782c6ab3462f1304ba3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0fae80b8706cf2def97794fc32f0aaae92efd3bc403dd9904e7be1370b05b84c4670ba25d4b64ca3aeb3af3135a83ae4c60577904d724678c8b8d48bfed2c593
|
7
|
+
data.tar.gz: 996746983caeeef7ce305533c5d564e375656cbd4787a8e9698d56fc5f2ba71cb6703fb93e33b672bb0f489ae75bc6269a5cd28d8921d0d758ff4699c8c22cb5
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# CSV <3 YAML Parser / Reader
|
2
2
|
|
3
|
-
csvyaml library / gem - read tabular data in the CSV <3 YAML format, that is, comma-separated values CSV
|
3
|
+
csvyaml library / gem - read tabular data in the CSV <3 YAML format, that is, comma-separated values (CSV) line-by-line records with yaml ain't markup language (YAML) encoding rules
|
4
4
|
|
5
|
-
* home :: [github.com/
|
6
|
-
* bugs :: [github.com/
|
5
|
+
* home :: [github.com/csvreader/csvyaml](https://github.com/csvreader/csvyaml)
|
6
|
+
* bugs :: [github.com/csvreader/csvyaml/issues](https://github.com/csvreader/csvyaml/issues)
|
7
7
|
* gem :: [rubygems.org/gems/csvyaml](https://rubygems.org/gems/csvyaml)
|
8
8
|
* rdoc :: [rubydoc.info/gems/csvyaml](http://rubydoc.info/gems/csvyaml)
|
9
9
|
* forum :: [wwwmake](http://groups.google.com/group/wwwmake)
|
10
10
|
|
11
11
|
|
12
|
+
|
12
13
|
## Usage
|
13
14
|
|
14
15
|
to be done
|
data/Rakefile
CHANGED
@@ -8,7 +8,7 @@ Hoe.spec 'csvyaml' do
|
|
8
8
|
self.summary = "csvyaml - read tabular data in the CSV <3 YAML format, that is, comma-separated values CSV (line-by-line) records with yaml ain't markup language (YAML) encoding rules"
|
9
9
|
self.description = summary
|
10
10
|
|
11
|
-
self.urls = ['https://github.com/
|
11
|
+
self.urls = ['https://github.com/csvreader/csvyaml']
|
12
12
|
|
13
13
|
self.author = 'Gerald Bauer'
|
14
14
|
self.email = 'wwwmake@googlegroups.com'
|
data/lib/csvyaml.rb
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'pp'
|
4
|
-
|
4
|
+
require 'yaml'
|
5
|
+
require 'logger'
|
5
6
|
|
6
7
|
## our own code
|
7
8
|
require 'csvyaml/version' # note: let version always go first
|
9
|
+
require 'csvyaml/parser'
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
## add some "alternative" shortcut aliases
|
14
|
+
CSV_YAML = CsvYaml
|
15
|
+
CSVYAML = CsvYaml
|
16
|
+
CSVY = CsvYaml
|
17
|
+
CsvY = CsvYaml
|
18
|
+
|
8
19
|
|
9
20
|
|
10
|
-
|
11
|
-
pp CsvYaml.root
|
21
|
+
puts CsvYaml.banner
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
|
4
|
+
class CsvYaml
|
5
|
+
|
6
|
+
###################################
|
7
|
+
## add simple logger with debug flag/switch
|
8
|
+
#
|
9
|
+
# use Parser.debug = true # to turn on
|
10
|
+
#
|
11
|
+
# todo/fix: use logutils instead of std logger - why? why not?
|
12
|
+
|
13
|
+
def self.build_logger()
|
14
|
+
l = Logger.new( STDOUT )
|
15
|
+
l.level = :info ## set to :info on start; note: is 0 (debug) by default
|
16
|
+
l
|
17
|
+
end
|
18
|
+
def self.logger() @@logger ||= build_logger; end
|
19
|
+
def logger() self.class.logger; end
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
def self.open( path, mode=nil, &block ) ## rename path to filename or name - why? why not?
|
26
|
+
|
27
|
+
## note: default mode (if nil/not passed in) to 'r:bom|utf-8'
|
28
|
+
f = File.open( path, mode ? mode : 'r:bom|utf-8' )
|
29
|
+
csv = new( f )
|
30
|
+
|
31
|
+
# handle blocks like Ruby's open()
|
32
|
+
if block_given?
|
33
|
+
begin
|
34
|
+
block.call( csv )
|
35
|
+
ensure
|
36
|
+
csv.close
|
37
|
+
end
|
38
|
+
else
|
39
|
+
csv
|
40
|
+
end
|
41
|
+
end # method self.open
|
42
|
+
|
43
|
+
|
44
|
+
def self.read( path )
|
45
|
+
open( path ) { |csv| csv.read }
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def self.foreach( path, &block )
|
50
|
+
csv = open( path )
|
51
|
+
|
52
|
+
if block_given?
|
53
|
+
begin
|
54
|
+
csv.each( &block )
|
55
|
+
ensure
|
56
|
+
csv.close
|
57
|
+
end
|
58
|
+
else
|
59
|
+
csv.to_enum ## note: caller (responsible) must close file!!!
|
60
|
+
## remove version without block given - why? why not?
|
61
|
+
## use Csv.open().to_enum or Csv.open().each
|
62
|
+
## or Csv.new( File.new() ).to_enum or Csv.new( File.new() ).each ???
|
63
|
+
end
|
64
|
+
end # method self.foreach
|
65
|
+
|
66
|
+
|
67
|
+
def self.parse( str_or_readable, &block )
|
68
|
+
csv = new( str_or_readable )
|
69
|
+
|
70
|
+
if block_given?
|
71
|
+
csv.each( &block ) ## note: caller (responsible) must close file!!! - add autoclose - why? why not?
|
72
|
+
else # slurp contents, if no block is given
|
73
|
+
csv.read ## note: caller (responsible) must close file!!! - add autoclose - why? why not?
|
74
|
+
end
|
75
|
+
end # method self.parse
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
def initialize( str_or_readable )
|
80
|
+
if str_or_readable.is_a?( String )
|
81
|
+
@input = str_or_readable # note: just needs each for each_line
|
82
|
+
else ## assume io
|
83
|
+
@input = str_or_readable
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
include Enumerable
|
90
|
+
|
91
|
+
def each( &block )
|
92
|
+
if block_given?
|
93
|
+
@input.each_line do |line|
|
94
|
+
|
95
|
+
logger.debug "line:" if logger.debug?
|
96
|
+
logger.debug line.pretty_inspect if logger.debug?
|
97
|
+
|
98
|
+
|
99
|
+
## note: chomp('') if is an empty string,
|
100
|
+
## it will remove all trailing newlines from the string.
|
101
|
+
## use line.sub(/[\n\r]*$/, '') or similar instead - why? why not?
|
102
|
+
line = line.chomp( '' )
|
103
|
+
line = line.strip ## strip leading and trailing whitespaces (space/tab) too
|
104
|
+
logger.debug line.pretty_inspect if logger.debug?
|
105
|
+
|
106
|
+
if line.empty? ## skip blank lines
|
107
|
+
logger.debug "skip blank line" if logger.debug?
|
108
|
+
next
|
109
|
+
end
|
110
|
+
|
111
|
+
if line.start_with?( "#" ) ## skip comment lines
|
112
|
+
logger.debug "skip comment line" if logger.debug?
|
113
|
+
next
|
114
|
+
end
|
115
|
+
|
116
|
+
## note: auto-wrap in array e.g. with []
|
117
|
+
## add document marker (---) why? why not?
|
118
|
+
values = YAML.load( "---\n[#{line}]" )
|
119
|
+
logger.debug values.pretty_inspect if logger.debug?
|
120
|
+
block.call( values )
|
121
|
+
end
|
122
|
+
else
|
123
|
+
to_enum
|
124
|
+
end
|
125
|
+
end # method each
|
126
|
+
|
127
|
+
def read() to_a; end # method read
|
128
|
+
|
129
|
+
def close
|
130
|
+
@input.close if @input.respond_to?(:close) ## note: string needs no close
|
131
|
+
end
|
132
|
+
|
133
|
+
end # class CsvYaml
|
data/lib/csvyaml/version.rb
CHANGED
data/test/helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
## $:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
## minitest setup
|
4
|
+
|
5
|
+
require 'minitest/autorun'
|
6
|
+
|
7
|
+
|
8
|
+
## our own code
|
9
|
+
require 'csvyaml'
|
10
|
+
|
11
|
+
|
12
|
+
## add test_data_dir helper
|
13
|
+
class CsvYaml
|
14
|
+
def self.test_data_dir
|
15
|
+
"#{root}/test/data"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
CsvYaml.logger.level = :debug ## turn on "global" logging
|
data/test/test_parser.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
###
|
4
|
+
# to run use
|
5
|
+
# ruby -I ./lib -I ./test test/test_parser.rb
|
6
|
+
|
7
|
+
|
8
|
+
require 'helper'
|
9
|
+
|
10
|
+
class TestParser < MiniTest::Test
|
11
|
+
|
12
|
+
|
13
|
+
def parser
|
14
|
+
CsvYaml
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def records ## "standard" records for testing
|
19
|
+
[[1, "John", "12 Totem Rd. Aspen", true],
|
20
|
+
[2, "Bob", nil, false],
|
21
|
+
[3, "Sue", "Bigsby, 345 Carnival, WA 23009", false]]
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
def test_parse
|
27
|
+
assert_equal records, parser.parse( <<TXT )
|
28
|
+
1,John,12 Totem Rd. Aspen,true
|
29
|
+
2,Bob,null,false
|
30
|
+
3,Sue,"Bigsby, 345 Carnival, WA 23009",false
|
31
|
+
TXT
|
32
|
+
|
33
|
+
assert_equal records, parser.parse( <<TXT )
|
34
|
+
# hello world
|
35
|
+
|
36
|
+
1,John,12 Totem Rd. Aspen,true
|
37
|
+
2,Bob,null,false
|
38
|
+
3,Sue,"Bigsby, 345 Carnival, WA 23009",false
|
39
|
+
TXT
|
40
|
+
|
41
|
+
assert_equal records, parser.parse( <<TXT )
|
42
|
+
# hello world (pretty printed)
|
43
|
+
|
44
|
+
1, John, 12 Totem Rd. Aspen, true
|
45
|
+
2, Bob, null, false
|
46
|
+
3, Sue, "Bigsby, 345 Carnival, WA 23009", false
|
47
|
+
|
48
|
+
# try more comments and empty lines
|
49
|
+
|
50
|
+
TXT
|
51
|
+
|
52
|
+
|
53
|
+
txt =<<TXT
|
54
|
+
# hello world
|
55
|
+
1,John,12 Totem Rd. Aspen,true
|
56
|
+
2,Bob,null,false
|
57
|
+
3,Sue,"Bigsby, 345 Carnival, WA 23009",false
|
58
|
+
TXT
|
59
|
+
|
60
|
+
recs = []
|
61
|
+
parser.parse( txt ) { |rec| recs << rec }
|
62
|
+
assert_equal records, recs
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def test_read
|
67
|
+
assert_equal records, parser.read( "#{CsvYaml.test_data_dir}/hello.yaml.csv" )
|
68
|
+
assert_equal records, parser.read( "#{CsvYaml.test_data_dir}/hello11.yaml.csv" )
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def test_open
|
73
|
+
assert_equal records, parser.open( "#{CsvYaml.test_data_dir}/hello.yaml.csv", "r:bom|utf-8" ).read
|
74
|
+
assert_equal records, parser.open( "#{CsvYaml.test_data_dir}/hello11.yaml.csv", "r:bom|utf-8" ).read
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def test_foreach
|
79
|
+
recs = []
|
80
|
+
parser.foreach( "#{CsvYaml.test_data_dir}/hello.yaml.csv" ) { |rec| recs << rec }
|
81
|
+
assert_equal records, recs
|
82
|
+
|
83
|
+
recs = []
|
84
|
+
parser.foreach( "#{CsvYaml.test_data_dir}/hello11.yaml.csv" ) { |rec| recs << rec }
|
85
|
+
assert_equal records, recs
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def test_enum
|
90
|
+
csv = CsvYaml.new( <<TXT )
|
91
|
+
# hello world
|
92
|
+
|
93
|
+
1,John,12 Totem Rd. Aspen,true
|
94
|
+
2,Bob,null,false
|
95
|
+
3,Sue,"Bigsby, 345 Carnival, WA 23009",false
|
96
|
+
TXT
|
97
|
+
|
98
|
+
it = csv.to_enum
|
99
|
+
assert_equal [1, "John", "12 Totem Rd. Aspen", true], it.next
|
100
|
+
assert_equal [2, "Bob", nil, false], it.next
|
101
|
+
assert_equal [3, "Sue", "Bigsby, 345 Carnival, WA 23009", false], it.next
|
102
|
+
end
|
103
|
+
|
104
|
+
end # class TestParser
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
###
|
4
|
+
# to run use
|
5
|
+
# ruby -I ./lib -I ./test test/test_parser_misc.rb
|
6
|
+
|
7
|
+
|
8
|
+
require 'helper'
|
9
|
+
|
10
|
+
class TestParserMisc < MiniTest::Test
|
11
|
+
|
12
|
+
|
13
|
+
def parser
|
14
|
+
CsvYaml
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def test_quotes_and_commas
|
19
|
+
assert_equal [
|
20
|
+
[1, "John", "12 Totem Rd., Aspen", true],
|
21
|
+
[2, "Bob", nil, false],
|
22
|
+
[3, "Sue", "\"Bigsby\", 345 Carnival, WA 23009", false]
|
23
|
+
], parser.parse( <<TXT )
|
24
|
+
1,John,"12 Totem Rd., Aspen",true
|
25
|
+
2,Bob,null,false
|
26
|
+
3,Sue,"\\"Bigsby\\", 345 Carnival, WA 23009",false
|
27
|
+
TXT
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def test_arrays
|
32
|
+
assert_equal [
|
33
|
+
[1, "directions", ["north","south","east","west"]],
|
34
|
+
[2, "colors", ["red","green","blue"]],
|
35
|
+
[3, "drinks", ["soda","water","tea","coffe"]],
|
36
|
+
[4, "spells", []],
|
37
|
+
], parser.parse( <<TXT )
|
38
|
+
# CSV <3 YAML with array values
|
39
|
+
|
40
|
+
1,directions,[north,south,east,west]
|
41
|
+
2,colors,[red,green,blue]
|
42
|
+
3,drinks,[soda,water,tea,coffe]
|
43
|
+
4,spells,[]
|
44
|
+
TXT
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_misc
|
48
|
+
## note:
|
49
|
+
## in the csv <3 json source text backslash needs to get doubled / escaped twice e.g.
|
50
|
+
## \\" for quotes
|
51
|
+
## \\n for newlines and so on
|
52
|
+
|
53
|
+
assert_equal [
|
54
|
+
["index", "value1", "value2"],
|
55
|
+
["number", 1, 2],
|
56
|
+
["boolean", false, true],
|
57
|
+
["null", nil, "non null"],
|
58
|
+
["array of numbers", [1], [1,2]],
|
59
|
+
["simple object", {"a" => 1}, {"a" => 1, "b" => 2}],
|
60
|
+
["array with mixed objects", [1, nil,"ball"], [2,{"a" => 10, "b" => 20},"cube"]],
|
61
|
+
["string with quotes", "a\"b", "alert(\"Hi!\")"],
|
62
|
+
["string with bell&newlines","bell is \u0007","multi\nline\ntext"]
|
63
|
+
], parser.parse( <<TXT )
|
64
|
+
# CSV with all kinds of values
|
65
|
+
|
66
|
+
index,value1,value2
|
67
|
+
number,1,2
|
68
|
+
boolean,false,true
|
69
|
+
"null",null,non null
|
70
|
+
array of numbers,[1],[1,2]
|
71
|
+
## note: key:value pairs need a space after colon!!! NOT working {a:1},{a:1, b:2}
|
72
|
+
simple object,{a: 1},{a: 1, b: 2}
|
73
|
+
## note: again - key:value pairs need a space after colon!!! NOT working {a:10, b:20}
|
74
|
+
array with mixed objects,[1,null,ball],[2,{a: 10,b: 20},cube]
|
75
|
+
string with quotes,"a\\"b","alert(\\"Hi!\\")"
|
76
|
+
string with bell&newlines,"bell is \\u0007","multi\\nline\\ntext"
|
77
|
+
TXT
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
end # class TestParserMisc
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csvyaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gerald Bauer
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rdoc
|
@@ -54,8 +54,14 @@ files:
|
|
54
54
|
- README.md
|
55
55
|
- Rakefile
|
56
56
|
- lib/csvyaml.rb
|
57
|
+
- lib/csvyaml/parser.rb
|
57
58
|
- lib/csvyaml/version.rb
|
58
|
-
|
59
|
+
- test/data/hello.yaml.csv
|
60
|
+
- test/data/hello11.yaml.csv
|
61
|
+
- test/helper.rb
|
62
|
+
- test/test_parser.rb
|
63
|
+
- test/test_parser_misc.rb
|
64
|
+
homepage: https://github.com/csvreader/csvyaml
|
59
65
|
licenses:
|
60
66
|
- Public Domain
|
61
67
|
metadata: {}
|