nodaire 0.2.0 → 0.3.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
  SHA256:
3
- metadata.gz: 57dbe680f2640d6fff1c929cc8b953a7bcb99bd173d207193231a752e50dfdfa
4
- data.tar.gz: b90ac2968b5ee9d26391228d1f1460a763bd409f879881991113e3286c68e542
3
+ metadata.gz: e9b7c87d8f3775b1d06a7cf203296efcf40bf95904ba9ed7e8a1f09d0d946e21
4
+ data.tar.gz: 2185bc3eea0363808665f4dbc6f6a04c7cb483544c92698dfd00200eee61673f
5
5
  SHA512:
6
- metadata.gz: c5606db3b3c3f5574024476681b5c5053d23274107dd88faa92211bade14d35acd3e9d5f1adc088681d6174ebe24ce66f2165138a864aa5d56efe89dfb20246d
7
- data.tar.gz: 0bb05b71c821062ce5bc5314491a3fa11b7b80f0aedef704c66a0fc7d972676a71e64da4fc72a21665e09acb3338e8396b29ce71454550cf740d02987b0b163d
6
+ metadata.gz: ac327bc203d061ee6bef827b3d43b5c3c6e8cd6f754c5e4cce9bf63dac8996452de348de057218c27da87170d45db9e8ca81f3d52ac25df8106136944940d867
7
+ data.tar.gz: '06508af2ec0ea395bc4b45c59c77d0b41490c6abf8cbc7ff565e86195b855e6bf24c4bcb2243d73a3da17f2e1b780ec04c50618709b41b0f098680503b148677'
data/README.md CHANGED
@@ -1,84 +1,91 @@
1
- # Nodaire
1
+ # Nodaire [![Gem Version](https://badge.fury.io/rb/nodaire.svg)](https://rubygems.org/gems/nodaire) [![Build Status](https://travis-ci.org/slisne/nodaire.svg?branch=master)](https://travis-ci.org/slisne/nodaire)
2
2
 
3
- Ruby parsers for text file formats. Work in progress.
3
+ Nodaire is a collection of text file parsers.
4
+ It supports Ruby 2.5.0 or greater.
4
5
 
5
- [![Gem Version](https://badge.fury.io/rb/nodaire.svg)](https://rubygems.org/gems/nodaire)
6
+ __Note__: This is a new gem, and the interface is not yet stable.
7
+ Expect breaking API changes before v1.0.0 is released.
6
8
 
7
9
  ## File formats
8
10
 
9
- - [Oscean](https://wiki.xxiivv.com/#oscean) file formats by Devine Lu Linvega:
10
- - [__Indental__](https://wiki.xxiivv.com/#indental) (.ndtl)
11
- - [__Tablatal__](https://wiki.xxiivv.com/#tablatal) (.tbtl)
11
+ Nodaire currently supports the following text file formats:
12
12
 
13
- ## Examples
13
+ - __Indental__ — <https://wiki.xxiivv.com/#indental>
14
+ - __Tablatal__ — <https://wiki.xxiivv.com/#tablatal>
15
+
16
+ ## Install
17
+
18
+ Install `nodaire` from [RubyGems](https://rubygems.org/gems/nodaire):
19
+
20
+ ```sh
21
+ gem install nodaire
22
+ ```
23
+
24
+ ## Documentation
25
+
26
+ [Code documentation](https://slisne.github.io/nodaire/) is available.
27
+
28
+ Keep reading below for examples of how to use Nodaire.
29
+
30
+ ## Usage examples
14
31
 
15
32
  ### Indental
16
33
 
17
34
  ```ruby
18
- > input = <<~NDTL
35
+ require 'nodaire/indental'
36
+
37
+ doc = Nodaire::Indental.parse! <<~NDTL
19
38
  NAME
20
39
  KEY : VALUE
21
40
  LIST
22
41
  ITEM1
23
42
  ITEM2
24
- NDTL
43
+ NDTL
25
44
 
26
- > indental = Nodaire::Indental.parse(input)
27
-
28
- > indental.data
29
- # {
30
- # name: {
31
- # key: 'VALUE',
32
- # list: ['ITEM1', 'ITEM2'],
33
- # },
34
- # }
35
-
36
- > indental.valid?
37
- # true
38
-
39
- > indental = Nodaire::Indental.parse(input, preserve_keys: true)
40
-
41
- > indental.to_json
42
- # {"NAME":{"KEY":"VALUE","LIST":["ITEM1","ITEM2"]}}
45
+ doc.valid? # true
46
+ doc.categories # ["NAME"]
47
+ doc.to_h # {"NAME"=>{"KEY"=>"VALUE", "LIST"=>["ITEM1", "ITEM2"]}}
48
+ doc.to_json # '{"NAME":{"KEY":"VALUE","LIST":["ITEM1","ITEM2"]}}'
43
49
  ```
44
50
 
45
51
  ### Tablatal
46
52
 
47
53
  ```ruby
48
- > input = <<~TBTL
54
+ require 'nodaire/tablatal'
55
+
56
+ doc = Nodaire::Tablatal.parse! <<~TBTL
49
57
  NAME AGE COLOR
50
58
  Erica 12 Opal
51
59
  Alex 23 Cyan
52
60
  Nike 34 Red
53
61
  Ruca 45 Grey
54
- TBTL
62
+ TBTL
55
63
 
56
- > tablatal = Nodaire::Tablatal.parse(input)
57
-
58
- > tablatal.data
59
- # [
60
- # { name: 'Erica', age: '12', color: 'Opal' },
61
- # { name: 'Alex', age: '23', color: 'Cyan' },
62
- # { name: 'Nike', age: '34', color: 'Red' },
63
- # { name: 'Ruca', age: '45', color: 'Grey' },
64
- # ]
64
+ doc.valid? # true
65
+ doc.keys # ["NAME", "AGE", "COLOR"]
66
+ doc.to_a.last # {"NAME"=>"Ruca", "AGE"=>"45", "COLOR"=>"Grey"}
67
+ doc.to_csv # "NAME,AGE,COLOR\nErica,12,Opal\nAlex,23,..."
68
+ ```
65
69
 
66
- > tablatal.valid?
67
- # true
70
+ ## Development
68
71
 
69
- > tablatal = Nodaire::Tablatal.parse(input, preserve_keys: true)
72
+ To run the latest source code, check out the
73
+ [Git repository](https://github.com/slisne/nodaire):
70
74
 
71
- > tablatal.to_csv
72
- # NAME,AGE,COLOR
73
- # Erica,12,Opal
74
- # Alex,23,Cyan
75
- # Nike,34,Red
76
- # Ruca,45,Grey
75
+ ```sh
76
+ git clone https://github.com/slisne/nodaire.git
77
77
  ```
78
78
 
79
- ## Testing
79
+ Install the dependencies using Bundler:
80
80
 
81
+ ```sh
82
+ gem install bundler
83
+ bundle install
81
84
  ```
82
- bundle install --with test
85
+
86
+ Analyse the code and run unit tests using Bundler:
87
+
88
+ ```sh
89
+ bundle exec rubocop
83
90
  bundle exec rspec
84
91
  ```
data/lib/nodaire.rb CHANGED
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- ##
4
- # Nodaire is a collection of text file parsers.
5
- #
6
- module Nodaire
7
- end
8
-
9
- require_relative 'nodaire/formats'
10
-
3
+ require_relative 'nodaire/base'
11
4
  require_relative 'nodaire/errors'
12
- require_relative 'nodaire/version'
5
+
6
+ require_relative 'nodaire/indental'
7
+ require_relative 'nodaire/tablatal'
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ require_relative '../parsers/indental_parser'
6
+
7
+ ##
8
+ # Interface for documents in _Indental_ format.
9
+ #
10
+ # _Indental_ is a 'dictionary-type database format' by Devine Lu Linvega.
11
+ # See: https://wiki.xxiivv.com/#indental
12
+ #
13
+ # require 'nodaire/indental'
14
+ #
15
+ # doc = Nodaire::Indental.parse! <<~NDTL
16
+ # NAME
17
+ # KEY : VALUE
18
+ # LIST
19
+ # ITEM1
20
+ # ITEM2
21
+ # NDTL
22
+ #
23
+ # doc.valid? # true
24
+ # doc.categories # ["NAME"]
25
+ # doc.to_h # {"NAME"=>{"KEY"=>"VALUE", "LIST"=>["ITEM1", "ITEM2"]}}
26
+ # doc.to_json # '{"NAME":{"KEY":"VALUE","LIST":["ITEM1","ITEM2"]}}'
27
+ #
28
+ # @since 0.2.0
29
+ #
30
+ class Nodaire::Indental
31
+ # A hash containing the data parsed from the source.
32
+ # @return [Hash]
33
+ attr_reader :data
34
+ # An array of category names.
35
+ # @since 0.3.0
36
+ # @return [Array<String>]
37
+ attr_reader :categories
38
+ # An array of error messages.
39
+ # @return [Array<String>]
40
+ attr_reader :errors
41
+
42
+ alias_method :to_h, :data
43
+
44
+ ##
45
+ # Parse the document +source+.
46
+ #
47
+ # @param [String] source The document source to parse.
48
+ # @param [Boolean] symbolize_names
49
+ # If true, normalize category and key names and convert them to
50
+ # lowercase symbols.
51
+ #
52
+ # @return [Indental]
53
+ #
54
+ def self.parse(source, symbolize_names: false)
55
+ parser = Parser.new(source, false, symbolize_names: symbolize_names)
56
+
57
+ new(parser)
58
+ end
59
+
60
+ ##
61
+ # Parse the document +source+, raising an exception if a parser error occurs.
62
+ #
63
+ # @param [String] source The document source to parse.
64
+ # @param [boolean] symbolize_names
65
+ # If true, normalize category and key names and convert them to
66
+ # lowercase symbols.
67
+ #
68
+ # @raise [ParserError]
69
+ # @return [Indental]
70
+ #
71
+ def self.parse!(source, symbolize_names: false)
72
+ parser = Parser.new(source, true, symbolize_names: symbolize_names)
73
+
74
+ new(parser)
75
+ end
76
+
77
+ ##
78
+ # A boolean indicating whether the source was parsed without errors.
79
+ #
80
+ # @return [Boolean]
81
+ #
82
+ def valid?
83
+ @errors.empty?
84
+ end
85
+
86
+ ##
87
+ # Convert the document to JSON.
88
+ #
89
+ # @return [String]
90
+ #
91
+ def to_json(*_args)
92
+ JSON.generate(data)
93
+ end
94
+
95
+ private
96
+
97
+ def initialize(parser)
98
+ @data = parser.data
99
+ @errors = parser.errors
100
+
101
+ @categories = data.keys
102
+ end
103
+ end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'csv'
4
+
5
+ require_relative '../parsers/tablatal_parser'
6
+
7
+ ##
8
+ # Interface for documents in _Tablatal_ format.
9
+ #
10
+ # _Tablatal_ is a 'list-type database format' by Devine Lu Linvega.
11
+ # See: https://wiki.xxiivv.com/#tablatal
12
+ #
13
+ # require 'nodaire/tablatal'
14
+ #
15
+ # doc = Nodaire::Tablatal.parse! <<~TBTL
16
+ # NAME AGE COLOR
17
+ # Erica 12 Opal
18
+ # Alex 23 Cyan
19
+ # Nike 34 Red
20
+ # Ruca 45 Grey
21
+ # TBTL
22
+ #
23
+ # doc.valid? # true
24
+ # doc.keys # ["NAME", "AGE", "COLOR"]
25
+ # doc.to_a.last # {"NAME"=>"Ruca", "AGE"=>"45", "COLOR"=>"Grey"}
26
+ # doc.to_csv # "NAME,AGE,COLOR\nErica,12,Opal\nAlex,23,..."
27
+ #
28
+ # @since 0.1.0
29
+ #
30
+ class Nodaire::Tablatal
31
+ # An array of hashes containing the data parsed from the source.
32
+ # @return [Array<Hash>]
33
+ attr_reader :data
34
+ # An array of keys parsed from the source header line.
35
+ # @return [Array]
36
+ attr_reader :keys
37
+ # An array of error message strings.
38
+ # @since 0.2.0
39
+ # @return [Array<String>]
40
+ attr_reader :errors
41
+
42
+ alias_method :to_a, :data
43
+
44
+ ##
45
+ # Parse the document +source+.
46
+ #
47
+ # @param [String] source The document source to parse.
48
+ # @param [Boolean] symbolize_names
49
+ # If true, normalize key names and convert them to lowercase symbols.
50
+ #
51
+ # @since 0.2.0
52
+ # @return [Tablatal]
53
+ #
54
+ def self.parse(source, symbolize_names: false)
55
+ parser = Parser.new(source, false, symbolize_names: symbolize_names)
56
+
57
+ new(parser)
58
+ end
59
+
60
+ ##
61
+ # Parse the document +source+, raising an exception if a parser error occurs.
62
+ #
63
+ # @param [String] source The document source to parse.
64
+ # @param [Boolean] symbolize_names
65
+ # If true, normalize key names and convert them to lowercase symbols.
66
+ #
67
+ # @since 0.2.0
68
+ # @raise [ParserError]
69
+ # @return [Tablatal]
70
+ #
71
+ def self.parse!(source, symbolize_names: false)
72
+ parser = Parser.new(source, true, symbolize_names: symbolize_names)
73
+
74
+ new(parser)
75
+ end
76
+
77
+ ##
78
+ # A boolean indicating whether the source was parsed without errors.
79
+ #
80
+ # @since 0.2.0
81
+ # @return [Boolean]
82
+ #
83
+ def valid?
84
+ @errors.empty?
85
+ end
86
+
87
+ ##
88
+ # Convert the document to CSV.
89
+ #
90
+ # @return [String]
91
+ #
92
+ def to_csv
93
+ CSV.generate do |csv|
94
+ csv << keys
95
+ data.each do |row|
96
+ csv << keys.map { |key| row[key] }
97
+ end
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def initialize(parser)
104
+ @data = parser.data
105
+ @keys = parser.keys
106
+ @errors = parser.errors
107
+ end
108
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # Nodaire is a collection of text file parsers.
5
+ #
6
+ module Nodaire
7
+ # The version number.
8
+ VERSION = '0.3.0'
9
+ # The date when this version was released.
10
+ DATE = '2019-08-18'
11
+ end
@@ -1,5 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Nodaire
4
+ ##
5
+ # This exception is raised if a parser error occurs.
6
+ #
4
7
  class ParserError < StandardError; end
5
8
  end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'api/indental'
@@ -1,30 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../errors'
3
+ require_relative 'parser'
4
4
 
5
5
  class Nodaire::Indental
6
- class ParserError < Nodaire::ParserError; end
7
-
8
- class Parser
9
- attr_reader :data, :errors
6
+ # @private
7
+ class Parser < Nodaire::Parser
8
+ attr_reader :data
10
9
 
11
10
  def initialize(string, strict, options = {})
12
- @strict = strict
13
- @preserve_keys = options.fetch(:preserve_keys, false)
11
+ super(strict, options)
14
12
 
13
+ @symbolize_names = option(:symbolize_names, false)
15
14
  @data = {}
16
- @errors = []
15
+ @category_ids = {}
16
+ @category = nil
17
17
 
18
18
  parse! string
19
19
  end
20
20
 
21
21
  private
22
22
 
23
+ Category = Struct.new(:name, :key_ids, :list_id, keyword_init: true)
24
+
25
+ attr_accessor :category
26
+ attr_reader :symbolize_names, :category_ids
27
+
23
28
  def parse!(string)
29
+ lines = lines_to_parse(string)
30
+ lines = lines[1...-1] if js_wrapper?(lines)
31
+ lines.each { |line, num| parse_line! line, num }
32
+ end
33
+
34
+ def lines_to_parse(string)
24
35
  (string || '')
25
36
  .split("\n").each_with_index
26
37
  .reject { |line, _| line.match(/^\s*(;.*)?$/) }
27
- .each { |line, idx| parse_line! line, idx + 1 }
38
+ .map { |line, idx| [line, idx + 1] }
39
+ end
40
+
41
+ def js_wrapper?(lines)
42
+ !lines.empty? &&
43
+ lines.first[0].match(/=\s*`\s*$/) &&
44
+ lines.last[0].strip == '`'
28
45
  end
29
46
 
30
47
  def parse_line!(line, num)
@@ -37,67 +54,76 @@ class Nodaire::Indental
37
54
  end
38
55
 
39
56
  def parse_category!(cat, num)
40
- cat = symbolize_key(cat)
41
- if data.include?(cat)
42
- @cat_id = nil
43
- @list_id = nil
57
+ id = normalize_sym(cat)
58
+
59
+ if category_ids.include?(id)
44
60
  oops! 'Duplicate category', num
61
+ self.category = nil
45
62
  else
46
- @data[cat] = {}
47
- @cat_id = cat
48
- @list_id = nil
63
+ self.category = Category.new(
64
+ name: symbolize_names ? id : normalize_text(cat),
65
+ key_ids: {},
66
+ list_id: nil
67
+ )
68
+ data[category.name] = {}
69
+ category_ids[id] = category.name
49
70
  end
50
71
  end
51
72
 
52
73
  def parse_key_or_list!(line, num)
53
- return oops!('No category specified', num) unless @cat_id
74
+ return oops!('No category specified', num) if category.nil?
54
75
 
55
76
  if line.include?(' : ')
56
77
  key, value = line.split(' : ', 2)
57
- parse_key_value!(key.strip, value.strip, num)
78
+ parse_key_value!(key, value, num)
58
79
  else
59
80
  parse_list!(line, num)
60
81
  end
61
82
  end
62
83
 
63
84
  def parse_key_value!(key, value, num)
64
- key = symbolize_key(key)
65
- if @data[@cat_id].include?(key)
66
- @list_id = nil
85
+ id = normalize_sym(key)
86
+ key_name = symbolize_names ? id : normalize_text(key)
87
+
88
+ if category.key_ids.include?(id)
67
89
  oops! 'Duplicate key', num
68
90
  else
69
- @data[@cat_id][key] = value.strip
70
- @list_id = nil
91
+ data[category.name][key_name] = normalize_text(value)
92
+ category.key_ids[id] = key_name
71
93
  end
94
+
95
+ category.list_id = nil
72
96
  end
73
97
 
74
98
  def parse_list!(key, num)
75
- key = symbolize_key(key)
76
- if @data[@cat_id].include?(key)
77
- @list_id = nil
78
- oops! 'Duplicate key', num
99
+ id = normalize_sym(key)
100
+ list_name = symbolize_names ? id : normalize_text(key)
101
+
102
+ if category.key_ids.include?(id)
103
+ oops! 'Duplicate key for list', num
104
+ category.list_id = nil
79
105
  else
80
- @data[@cat_id][key] = []
81
- @list_id = key
106
+ data[category.name][list_name] = []
107
+ category.key_ids[id] = list_name
108
+ category.list_id = id
82
109
  end
83
110
  end
84
111
 
85
112
  def parse_list_item!(item, num)
86
- if @list_id.nil?
113
+ if category.nil? || category.list_id.nil?
87
114
  oops! 'No list specified', num
88
115
  else
89
- @data[@cat_id][@list_id] << item
116
+ list_name = category.key_ids[category.list_id]
117
+ data[category.name][list_name] << normalize_text(item)
90
118
  end
91
119
  end
92
120
 
93
- def oops!(message, line_num)
94
- message = "#{message} on line #{line_num}"
95
- @errors << message
96
- raise ParserError, message if @strict
121
+ def normalize_text(string)
122
+ string.split.join(' ')
97
123
  end
98
124
 
99
- def symbolize_key(key)
100
- @preserve_keys ? key : key.downcase.split.join('_').to_sym
125
+ def normalize_sym(key)
126
+ key.downcase.gsub(/[\s_-]+/, ' ').split.join('_').to_sym
101
127
  end
102
128
  end
103
129
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors'
4
+
5
+ # @private
6
+ class Nodaire::Parser
7
+ attr_reader :errors, :options
8
+
9
+ def initialize(strict, options = {})
10
+ @strict = strict
11
+ @options = options
12
+ @errors = []
13
+ end
14
+
15
+ def strict?
16
+ @strict
17
+ end
18
+
19
+ def option(name, default = nil)
20
+ @options.fetch(name, default)
21
+ end
22
+
23
+ def oops!(message, line_num)
24
+ message = "#{message} on line #{line_num}" unless line_num.nil?
25
+ errors << message
26
+ raise Nodaire::ParserError, message if strict?
27
+ end
28
+ end
@@ -1,28 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../errors'
3
+ require_relative 'parser'
4
4
 
5
5
  class Nodaire::Tablatal
6
- class ParserError < Nodaire::ParserError; end
7
-
8
- class Parser
9
- attr_reader :data, :errors
6
+ # @private
7
+ class Parser < Nodaire::Parser
8
+ attr_reader :data
10
9
 
11
10
  def initialize(string, strict, options = {})
12
- @strict = strict
13
- @preserve_keys = options.fetch(:preserve_keys, false)
11
+ super(strict, options)
12
+
13
+ @symbolize_names = option(:symbolize_names, false)
14
14
 
15
- @errors = []
15
+ @data = []
16
+ @keys = []
17
+ @key_ids = {}
16
18
 
17
19
  parse! string
18
20
  end
19
21
 
20
22
  def keys
21
- @keys.map(&:name) if @keys
23
+ @keys.map(&:name)
22
24
  end
23
25
 
24
26
  private
25
27
 
28
+ attr_reader :symbolize_names, :key_ids
29
+
26
30
  Key = Struct.new(:name, :range, keyword_init: true)
27
31
 
28
32
  def parse!(string)
@@ -31,20 +35,23 @@ class Nodaire::Tablatal
31
35
  return if lines.empty?
32
36
 
33
37
  @keys = make_keys(lines.shift.scan(/(\S+\s*)/).flatten)
34
- @data = lines.map { |line, num| make_line(line, num) }.compact
38
+ @data = lines.map { |line| make_line(line) }.compact
35
39
  end
36
40
 
37
41
  def make_keys(segs)
38
42
  [].tap do |keys|
39
43
  start = 0
40
44
  segs.each_with_index do |seg, idx|
41
- key = symbolize_key(seg.strip)
42
45
  len = seg.size if idx < segs.size - 1
46
+ id = normalize_sym(seg)
47
+ key_name = symbolize_names ? id : normalize_text(seg)
43
48
 
44
- if keys.any? { |k| key == k.name }
45
- oops! "Duplicate key #{key}", 1
49
+ if key_ids.include?(id)
50
+ oops! "Duplicate key #{key_name}", 1
46
51
  else
47
- keys << Key.new(name: key, range: start...(len && start + len))
52
+ range_end = len ? start + len - 1 : -1
53
+ key_ids[id] = key_name
54
+ keys << Key.new(name: key_name, range: start..range_end)
48
55
  end
49
56
 
50
57
  start += len if len
@@ -52,18 +59,16 @@ class Nodaire::Tablatal
52
59
  end
53
60
  end
54
61
 
55
- def make_line(line, num)
56
- @keys.map { |key| [key.name, (line[key.range] || '').strip] }.to_h
62
+ def make_line(line)
63
+ @keys.map { |key| [key.name, normalize_text(line[key.range])] }.to_h
57
64
  end
58
65
 
59
- def oops!(message, line_num)
60
- message = "#{message} on line #{line_num}"
61
- @errors << message
62
- raise ParserError, message if @strict
66
+ def normalize_text(string)
67
+ string ? string.split.join(' ') : ''
63
68
  end
64
69
 
65
- def symbolize_key(key)
66
- @preserve_keys ? key : key.downcase.to_sym
70
+ def normalize_sym(key)
71
+ key.downcase.gsub(/[_-]+/, ' ').split.join('_').to_sym
67
72
  end
68
73
  end
69
74
  end
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require_relative 'api/tablatal'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nodaire
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Liam Cooke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-17 00:00:00.000000000 Z
11
+ date: 2019-08-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Nodaire is a collection of text file parsers.
14
14
  email: nodaire@liamcooke.com
@@ -19,22 +19,24 @@ files:
19
19
  - LICENSE
20
20
  - README.md
21
21
  - lib/nodaire.rb
22
+ - lib/nodaire/api/indental.rb
23
+ - lib/nodaire/api/tablatal.rb
24
+ - lib/nodaire/base.rb
22
25
  - lib/nodaire/errors.rb
23
- - lib/nodaire/formats.rb
24
- - lib/nodaire/formats/indental.rb
25
- - lib/nodaire/formats/tablatal.rb
26
+ - lib/nodaire/indental.rb
26
27
  - lib/nodaire/parsers/indental_parser.rb
28
+ - lib/nodaire/parsers/parser.rb
27
29
  - lib/nodaire/parsers/tablatal_parser.rb
28
- - lib/nodaire/version.rb
29
- homepage: https://github.com/ljcooke/nodaire
30
+ - lib/nodaire/tablatal.rb
31
+ homepage: https://github.com/slisne/nodaire
30
32
  licenses:
31
33
  - MIT
32
34
  metadata:
33
- bug_tracker_uri: https://github.com/ljcooke/nodaire/issues
34
- changelog_uri: https://github.com/ljcooke/nodaire/blob/master/CHANGELOG.md
35
- documentation_uri: https://github.com/ljcooke/nodaire
36
- homepage_uri: https://github.com/ljcooke/nodaire
37
- source_code_uri: https://github.com/ljcooke/nodaire
35
+ bug_tracker_uri: https://github.com/slisne/nodaire/issues
36
+ changelog_uri: https://github.com/slisne/nodaire/blob/master/CHANGELOG.md
37
+ documentation_uri: https://slisne.github.io/nodaire/
38
+ homepage_uri: https://github.com/slisne/nodaire
39
+ source_code_uri: https://github.com/slisne/nodaire
38
40
  post_install_message:
39
41
  rdoc_options: []
40
42
  require_paths:
@@ -43,14 +45,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
43
45
  requirements:
44
46
  - - ">="
45
47
  - !ruby/object:Gem::Version
46
- version: '0'
48
+ version: 2.5.0
47
49
  required_rubygems_version: !ruby/object:Gem::Requirement
48
50
  requirements:
49
51
  - - ">="
50
52
  - !ruby/object:Gem::Version
51
53
  version: '0'
52
54
  requirements: []
53
- rubygems_version: 3.0.3
55
+ rubyforge_project:
56
+ rubygems_version: 2.7.3
54
57
  signing_key:
55
58
  specification_version: 4
56
59
  summary: Text file parsers.
@@ -1,4 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'formats/indental'
4
- require_relative 'formats/tablatal'
@@ -1,58 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'json'
4
-
5
- require_relative '../parsers/indental_parser'
6
-
7
- ##
8
- # Interface for the Indental file format.
9
- #
10
- # Indental is (c) Devine Lu Linvega (MIT License).
11
- #
12
- class Nodaire::Indental
13
- attr_reader :data, :errors
14
- alias_method :to_h, :data
15
-
16
- ##
17
- # Parse a string in Indental format.
18
- #
19
- # Ignores or attempts to work around errors.
20
- #
21
- def self.parse(string, preserve_keys: false)
22
- parser = Parser.new(string, false, preserve_keys: preserve_keys)
23
-
24
- new(parser)
25
- end
26
-
27
- ##
28
- # Parse a string in Indental format.
29
- #
30
- # Raises an exception if there are errors.
31
- #
32
- def self.parse!(string, preserve_keys: false)
33
- parser = Parser.new(string, true, preserve_keys: preserve_keys)
34
-
35
- new(parser)
36
- end
37
-
38
- ##
39
- # Returns whether the input was parsed without errors.
40
- #
41
- def valid?
42
- @errors.empty?
43
- end
44
-
45
- ##
46
- # Return a string in JSON format.
47
- #
48
- def to_json
49
- JSON.generate(data)
50
- end
51
-
52
- private
53
-
54
- def initialize(parser)
55
- @data = parser.data
56
- @errors = parser.errors
57
- end
58
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'csv'
4
-
5
- require_relative '../parsers/tablatal_parser'
6
-
7
- ##
8
- # Interface for the Tablatal file format.
9
- #
10
- # Tablatal is (c) Devine Lu Linvega (MIT License).
11
- #
12
- class Nodaire::Tablatal
13
- attr_reader :data, :keys, :errors
14
- alias_method :to_a, :data
15
-
16
- ##
17
- # Parse a string in Tablatal format.
18
- #
19
- # Ignores or attempts to work around errors.
20
- #
21
- def self.parse(string, preserve_keys: false)
22
- parser = Parser.new(string, false, preserve_keys: preserve_keys)
23
-
24
- new(parser)
25
- end
26
-
27
- ##
28
- # Parse a string in Tablatal format.
29
- #
30
- # Raises an exception if there are errors.
31
- #
32
- def self.parse!(string, preserve_keys: false)
33
- parser = Parser.new(string, true, preserve_keys: preserve_keys)
34
-
35
- new(parser)
36
- end
37
-
38
- ##
39
- # Returns whether the input was parsed without errors.
40
- #
41
- def valid?
42
- @errors.empty?
43
- end
44
-
45
- ##
46
- # Return a string in CSV format.
47
- #
48
- def to_csv
49
- CSV.generate do |csv|
50
- csv << keys
51
- data.each do |row|
52
- csv << keys.map { |key| row[key] }
53
- end
54
- end
55
- end
56
-
57
- private
58
-
59
- def initialize(parser)
60
- @data = parser.data
61
- @keys = parser.keys
62
- @errors = parser.errors
63
- end
64
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Nodaire
4
- module Version
5
- STRING = '0.2.0'
6
- DATE = '2019-08-17'
7
- end
8
- end