csvyaml 0.0.1 → 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 +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: {}
|