nestedtext 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,161 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "nestedtext/errors"
4
+
5
+ module NestedText
6
+ class LineScanner
7
+ def initialize(io)
8
+ @io = io
9
+ @next_line = nil
10
+ prepare_next_line
11
+ end
12
+
13
+ def empty?
14
+ @next_line.nil?
15
+ end
16
+
17
+ def read_next
18
+ raise Errors::LineScannerIsEmpty if empty?
19
+
20
+ line = @next_line
21
+ prepare_next_line
22
+ line.prev.prev = nil unless line.prev.nil? # GC: break the chain
23
+ line
24
+ end
25
+
26
+ def peek
27
+ @next_line
28
+ end
29
+
30
+ private
31
+
32
+ def prepare_next_line
33
+ line = nil
34
+ loop do
35
+ linestr = @io.gets&.chomp
36
+ lineno = @io.lineno - 1 # Be 0-based
37
+ line = linestr.nil? ? nil : Line.new(linestr, lineno, @next_line)
38
+ break if line.nil? || !%i[blank comment].include?(line.tag)
39
+ end
40
+ @next_line = line
41
+ end
42
+ end
43
+
44
+ class InlineScanner
45
+ attr_reader :line, :pos
46
+
47
+ def initialize(line)
48
+ @line = line
49
+ @pos = 0
50
+ end
51
+
52
+ def empty?
53
+ @pos >= @line.content.length
54
+ end
55
+
56
+ def remaining
57
+ @line.content[@pos..]
58
+ end
59
+
60
+ def read_next
61
+ raise Errors::InlineScannerIsEmpty if empty?
62
+
63
+ @pos += 1
64
+ @line.content[@pos - 1]
65
+ end
66
+
67
+ def peek
68
+ empty? ? nil : @line.content[@pos]
69
+ end
70
+ end
71
+
72
+ class Line
73
+ # Reference: https://nestedtext.org/en/latest/file_format.html
74
+ ALLOWED_LINE_TAGS = [
75
+ :comment, # a comment
76
+ :blank,
77
+ :list_item, # - item
78
+ :dict_item, # key: value (or value on next line)
79
+ :string_item, # > a string, can continue next line
80
+ :key_item, # : key on a line
81
+ :inline_dict, # {key1: value1, key2: value2}
82
+ :inline_list, # [value1, value2]
83
+ :unrecognized # could not be determined
84
+ ]
85
+
86
+ attr_accessor :prev
87
+ attr_reader :tag, :content, :indentation, :attribs, :lineno
88
+
89
+ def initialize(content, lineno, prev_line)
90
+ @content = content
91
+ @lineno = lineno
92
+ @prev = prev_line
93
+ @attribs = Hash.new(nil)
94
+ @tag = nil
95
+ @indentation = 0
96
+ detect_line_tag_and_indentation
97
+ end
98
+
99
+ # def length
100
+ # @content.length
101
+ # end
102
+
103
+ # def [](index)
104
+ # @content[index]
105
+ # end
106
+
107
+ def tag=(tag)
108
+ @tag = tag
109
+ raise Errors::LineTagUnknown.new(self, tag) unless ALLOWED_LINE_TAGS.include?(@tag)
110
+ end
111
+
112
+ def to_s
113
+ "[##{@lineno}] #{" " * @indentation}#{@content}"
114
+ end
115
+
116
+ private
117
+
118
+ # TODO: this regex must unit tested.
119
+ PATTERN_DICT_ITEM = /^
120
+ (?<key>[^\s].*?) # Key must start with a non-whitespace character, and goes until first
121
+ \s*: # first optional space, or :-separator
122
+ (?: # Value part is optional
123
+ \p{Space} # Must have a space after :-separator
124
+ (?<value>.*) # Value is everything to the end of the line
125
+ )?
126
+ $/x
127
+
128
+ def detect_line_tag_and_indentation
129
+ @indentation += 1 while @indentation < @content.length && @content[@indentation] == " "
130
+ @content = @content[@indentation..]
131
+
132
+ if @content.length == 0
133
+ self.tag = :blank
134
+ elsif @content[0] == "#"
135
+ self.tag = :comment
136
+ elsif @content =~ /^:(?: |$)/
137
+ self.tag = :key_item
138
+ @attribs["key"] = @content[2..] || ""
139
+ elsif @content =~ /^-(?: |$)/
140
+ self.tag = :list_item
141
+ @attribs["value"] = @content[2..]
142
+ elsif @content =~ /^>(?: |$)/
143
+ self.tag = :string_item
144
+ @attribs["value"] = @content[2..] || ""
145
+ elsif @content[0] == "{"
146
+ self.tag = :inline_dict
147
+ elsif @content[0] == "["
148
+ # TODO: merge path of inline dict and list and just set :inline?
149
+ self.tag = :inline_list
150
+ elsif @content =~ PATTERN_DICT_ITEM
151
+ self.tag = :dict_item
152
+ @attribs["key"] = Regexp.last_match(:key)
153
+ @attribs["value"] = Regexp.last_match(:value)
154
+ else
155
+ # Don't raise error here, as this line might not have been consumed yet,
156
+ # thus could hide an error that we detect when parsing the previous line.
157
+ self.tag = :unrecognized
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NestedText
4
+ VERSION = "0.1.0"
5
+ end
data/lib/nestedtext.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "nestedtext/encode"
4
+ require_relative "nestedtext/decode"
5
+ require_relative "nestedtext/core_ext"
6
+
7
+ module NestedText
8
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/nestedtext/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "nestedtext"
7
+ spec.version = NestedText::VERSION
8
+ spec.authors = ["Erik Westrup"]
9
+ spec.email = ["erik.westrup@gmail.com"]
10
+
11
+ spec.summary = "A ruby library for the human friendly data format NestedText https://nestedtext.org/"
12
+ spec.description = "A ruby implementation the NestedText data format. There is support for decoding a NestedText file or string to Ruby data structures, as well as encoding Ruby objects to a NestedText file or string. Furthermore there is support for serialization and deserialization of custom classes. Support for v3.2.1 of the data format will all official tests passing."
13
+ spec.homepage = "https://github.com/erikw/nestedtext-ruby/"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = [">= 3.0", "< 4"]
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/erikw/nestedtext-ruby/"
19
+ spec.metadata["changelog_uri"] = "https://github.com/erikw/nestedtext-ruby/blob/main/CHANGELOG.md"
20
+
21
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
+ `git ls-files -z`.split("\x0").reject do |f|
23
+ f.match(%r{\A(?:test/|script/|\.github/|\.gitmodules|Rakefile|TODO\.txt|\.codeclimate\.yml|\.vimlocal|\.simplecov)})
24
+ end
25
+ end
26
+ spec.require_paths = ["lib"]
27
+ end
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nestedtext
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Erik Westrup
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-24 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A ruby implementation the NestedText data format. There is support for
14
+ decoding a NestedText file or string to Ruby data structures, as well as encoding
15
+ Ruby objects to a NestedText file or string. Furthermore there is support for serialization
16
+ and deserialization of custom classes. Support for v3.2.1 of the data format will
17
+ all official tests passing.
18
+ email:
19
+ - erik.westrup@gmail.com
20
+ executables: []
21
+ extensions: []
22
+ extra_rdoc_files: []
23
+ files:
24
+ - ".editorconfig"
25
+ - ".gitignore"
26
+ - ".rubocop.yml"
27
+ - ".ruby-version"
28
+ - CHANGELOG.md
29
+ - CONTRIBUTING.md
30
+ - Gemfile
31
+ - LICENSE.txt
32
+ - OSSMETADATA
33
+ - README.md
34
+ - SECURITY.md
35
+ - lib/nestedtext.rb
36
+ - lib/nestedtext/constants.rb
37
+ - lib/nestedtext/core_ext.rb
38
+ - lib/nestedtext/decode.rb
39
+ - lib/nestedtext/dumper.rb
40
+ - lib/nestedtext/encode.rb
41
+ - lib/nestedtext/encode_helpers.rb
42
+ - lib/nestedtext/errors.rb
43
+ - lib/nestedtext/helpers.rb
44
+ - lib/nestedtext/parser.rb
45
+ - lib/nestedtext/scanners.rb
46
+ - lib/nestedtext/version.rb
47
+ - nestedtext.gemspec
48
+ homepage: https://github.com/erikw/nestedtext-ruby/
49
+ licenses:
50
+ - MIT
51
+ metadata:
52
+ homepage_uri: https://github.com/erikw/nestedtext-ruby/
53
+ source_code_uri: https://github.com/erikw/nestedtext-ruby/
54
+ changelog_uri: https://github.com/erikw/nestedtext-ruby/blob/main/CHANGELOG.md
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '3.0'
64
+ - - "<"
65
+ - !ruby/object:Gem::Version
66
+ version: '4'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubygems_version: 3.3.3
74
+ signing_key:
75
+ specification_version: 4
76
+ summary: A ruby library for the human friendly data format NestedText https://nestedtext.org/
77
+ test_files: []