yamlr 2.0.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.
- data/.autotest +25 -0
- data/.gemtest +0 -0
- data/History.txt +10 -0
- data/Manifest.txt +35 -0
- data/README.txt +53 -0
- data/Rakefile +24 -0
- data/bin/yamlr +68 -0
- data/lib/yamlr.rb +46 -0
- data/lib/yamlr/defaults.rb +78 -0
- data/lib/yamlr/errors.rb +8 -0
- data/lib/yamlr/indicators.rb +25 -0
- data/lib/yamlr/reader.rb +33 -0
- data/lib/yamlr/reader/builder.rb +249 -0
- data/lib/yamlr/reader/format.rb +116 -0
- data/lib/yamlr/reader/node.rb +53 -0
- data/lib/yamlr/reader/parser.rb +68 -0
- data/lib/yamlr/version.rb +3 -0
- data/lib/yamlr/writer.rb +47 -0
- data/lib/yamlr/writer/builder.rb +93 -0
- data/test/files/2009.yml +3 -0
- data/test/files/arrays.yml +15 -0
- data/test/files/blank.yml +0 -0
- data/test/files/comments.yml +17 -0
- data/test/files/hashes.yml +26 -0
- data/test/files/malformed.yml +3 -0
- data/test/files/mixed.yml +12 -0
- data/test/files/nested.yml +9 -0
- data/test/files/split.yml +9 -0
- data/test/test_reader.rb +210 -0
- data/test/test_reader_builder.rb +342 -0
- data/test/test_reader_format.rb +393 -0
- data/test/test_reader_parser.rb +190 -0
- data/test/test_writer.rb +133 -0
- data/test/test_writer_builder.rb +150 -0
- data/test/test_yamlr.rb +185 -0
- data/yamlr.gemspec +36 -0
- metadata +121 -0
data/.autotest
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require "autotest/restart"
|
4
|
+
|
5
|
+
# Autotest.add_hook :initialize do |at|
|
6
|
+
# at.testlib = "minitest/unit"
|
7
|
+
#
|
8
|
+
# at.extra_files << "../some/external/dependency.rb"
|
9
|
+
#
|
10
|
+
# at.libs << ":../some/external"
|
11
|
+
#
|
12
|
+
# at.add_exception "vendor"
|
13
|
+
#
|
14
|
+
# at.add_mapping(/dependency.rb/) do |f, _|
|
15
|
+
# at.files_matching(/test_.*rb$/)
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# %w(TestA TestB).each do |klass|
|
19
|
+
# at.extra_class_map[klass] = "test/test_misc.rb"
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
|
23
|
+
# Autotest.add_hook :run_command do |at|
|
24
|
+
# system "rake build"
|
25
|
+
# end
|
data/.gemtest
ADDED
File without changes
|
data/History.txt
ADDED
data/Manifest.txt
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
.autotest
|
2
|
+
History.txt
|
3
|
+
Manifest.txt
|
4
|
+
README.txt
|
5
|
+
Rakefile
|
6
|
+
bin/yamlr
|
7
|
+
lib/yamlr.rb
|
8
|
+
lib/yamlr/defaults.rb
|
9
|
+
lib/yamlr/errors.rb
|
10
|
+
lib/yamlr/indicators.rb
|
11
|
+
lib/yamlr/reader.rb
|
12
|
+
lib/yamlr/reader/builder.rb
|
13
|
+
lib/yamlr/reader/format.rb
|
14
|
+
lib/yamlr/reader/node.rb
|
15
|
+
lib/yamlr/reader/parser.rb
|
16
|
+
lib/yamlr/version.rb
|
17
|
+
lib/yamlr/writer.rb
|
18
|
+
lib/yamlr/writer/builder.rb
|
19
|
+
test/files/2009.yml
|
20
|
+
test/files/arrays.yml
|
21
|
+
test/files/blank.yml
|
22
|
+
test/files/comments.yml
|
23
|
+
test/files/hashes.yml
|
24
|
+
test/files/malformed.yml
|
25
|
+
test/files/mixed.yml
|
26
|
+
test/files/nested.yml
|
27
|
+
test/files/split.yml
|
28
|
+
test/test_reader.rb
|
29
|
+
test/test_reader_builder.rb
|
30
|
+
test/test_reader_format.rb
|
31
|
+
test/test_reader_parser.rb
|
32
|
+
test/test_writer.rb
|
33
|
+
test/test_writer_builder.rb
|
34
|
+
test/test_yamlr.rb
|
35
|
+
yamlr.gemspec
|
data/README.txt
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
= Yamlr
|
2
|
+
|
3
|
+
* http://github.com/step1profit/yamlr
|
4
|
+
* http://seattlerb.org
|
5
|
+
|
6
|
+
== DESCRIPTION:
|
7
|
+
|
8
|
+
Yamlr is a minimal YAML parser written in Ruby.
|
9
|
+
|
10
|
+
== FEATURES:
|
11
|
+
|
12
|
+
* Parse Array/Hash/String
|
13
|
+
* Read/write .yml files
|
14
|
+
* Dotfile configurable
|
15
|
+
* Serialize keys
|
16
|
+
* Robust command line support
|
17
|
+
* No variables or fancy YAML features
|
18
|
+
|
19
|
+
== INSTALLATION:
|
20
|
+
|
21
|
+
gem install yamlr
|
22
|
+
|
23
|
+
== SYNOPSIS:
|
24
|
+
|
25
|
+
* FIX (code sample of usage)
|
26
|
+
|
27
|
+
== REQUIREMENTS:
|
28
|
+
|
29
|
+
* ruby 1.9.3 or higher
|
30
|
+
|
31
|
+
== LICENSE:
|
32
|
+
|
33
|
+
The MIT License (MIT)
|
34
|
+
|
35
|
+
Copyright (c) 2008 - 2015 SoAwesomeMan, Step1Profit
|
36
|
+
|
37
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
38
|
+
of this software and associated documentation files (the "Software"), to deal
|
39
|
+
in the Software without restriction, including without limitation the rights
|
40
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
41
|
+
copies of the Software, and to permit persons to whom the Software is
|
42
|
+
furnished to do so, subject to the following conditions:
|
43
|
+
|
44
|
+
The above copyright notice and this permission notice shall be included in
|
45
|
+
all copies or substantial portions of the Software.
|
46
|
+
|
47
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
48
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
49
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
50
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
51
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
52
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
53
|
+
THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "hoe"
|
5
|
+
|
6
|
+
# Hoe.plugin :compiler
|
7
|
+
# Hoe.plugin :gem_prelude_sucks
|
8
|
+
# Hoe.plugin :inline
|
9
|
+
# Hoe.plugin :racc
|
10
|
+
# Hoe.plugin :rcov
|
11
|
+
|
12
|
+
# https://github.com/jbarnette/hoe-git
|
13
|
+
Hoe.plugin :git
|
14
|
+
Hoe.plugin :yard
|
15
|
+
# https://github.com/flavorjones/hoe-gemspec
|
16
|
+
Hoe.plugin :gemspec
|
17
|
+
|
18
|
+
Hoe.spec "yamlr" do
|
19
|
+
developer('Step1Profit', 'sales@step1profit.com')
|
20
|
+
|
21
|
+
license "MIT"
|
22
|
+
end
|
23
|
+
|
24
|
+
# vim: syntax=ruby
|
data/bin/yamlr
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'optparse'
|
4
|
+
require 'pp'
|
5
|
+
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
7
|
+
require 'yamlr'
|
8
|
+
|
9
|
+
module YamlrOpt
|
10
|
+
DESC = Yamlr::Defaults.descriptions
|
11
|
+
def self.command
|
12
|
+
hsh = {}
|
13
|
+
hsh[:opt] = {}
|
14
|
+
ops = nil
|
15
|
+
OptionParser.new do |opts|
|
16
|
+
opts.banner = "Yamlr #{Yamlr::VERSION}"
|
17
|
+
opts.on("-r", "--read FILENAME", String, String, ".yml file to Ruby Hash or Array") do |x|
|
18
|
+
hsh[:cmd] = 1
|
19
|
+
hsh[:arg] = [x]
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.on("-w", "--write FILENAME,FILENAME", Array, "Hash or Array => .yml file") do |x|
|
23
|
+
hsh[:cmd] = 2
|
24
|
+
hsh[:arg] = x
|
25
|
+
end
|
26
|
+
|
27
|
+
opts.on("-d", "--dotfile [HOME]", String, "Create .yamlrc dotfile") do |x|
|
28
|
+
x.nil? ? (y = Yamlr.dotfile) : (y = Yamlr.dotfile(x))
|
29
|
+
z = "#{File.dirname(y).chomp("/")}/.yamlrc"
|
30
|
+
puts "existed: #{z}, moved to: #{y}" if File.basename(y) != ".yamlrc"
|
31
|
+
puts "created: #{z}"
|
32
|
+
return
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.on("-v", "--version", "Display verison number") do
|
36
|
+
STDOUT.write("Yamlr #{Yamlr::VERSION}\n\r")
|
37
|
+
return
|
38
|
+
end
|
39
|
+
|
40
|
+
opts.on("-h", "--help", "Show this message") do
|
41
|
+
puts opts
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
Yamlr::Defaults.constants.sort.each do |x|
|
46
|
+
next if x == "DOTFILE"
|
47
|
+
opts.on("--[no-]#{x.downcase}", DESC[x.downcase]) do |y|
|
48
|
+
hsh[:opt]["#{x.downcase}".to_sym] = y
|
49
|
+
puts "use options with --read or --write" && return if hsh[:cmd].nil?
|
50
|
+
end
|
51
|
+
end
|
52
|
+
ops = opts
|
53
|
+
end.parse!
|
54
|
+
puts ops unless hsh.has_key?(:cmd)
|
55
|
+
return unless hsh.has_key?(:cmd)
|
56
|
+
self.run(hsh[:cmd], hsh[:arg], hsh[:opt])
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.run(cmd, arg, opt)
|
60
|
+
x = Yamlr.read(arg[0], opt)
|
61
|
+
case cmd
|
62
|
+
when 1 then pp x
|
63
|
+
when 2 then Yamlr.write(arg[0], arg[1], opt)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
YamlrOpt.command
|
data/lib/yamlr.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'yamlr/version'
|
2
|
+
require 'yamlr/reader'
|
3
|
+
require 'yamlr/writer'
|
4
|
+
require 'yamlr/indicators'
|
5
|
+
require 'yamlr/defaults'
|
6
|
+
|
7
|
+
module Yamlr
|
8
|
+
DOTFILE = "#{ENV['HOME']}/.yamlr"
|
9
|
+
|
10
|
+
# File to Hash or Array
|
11
|
+
#
|
12
|
+
def self.read(input, options = {})
|
13
|
+
Yamlr::Reader.read(input, self.options(options))
|
14
|
+
end
|
15
|
+
|
16
|
+
# Hash or Array to .yml Array
|
17
|
+
#
|
18
|
+
def self.parse(object, options = {})
|
19
|
+
Yamlr::Writer.build(object, self.options(options))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Hash or Array to .yml file, e.g. filename.yml
|
23
|
+
#
|
24
|
+
def self.write(object, filename, options = {})
|
25
|
+
Yamlr::Writer.write(object, filename, self.options(options))
|
26
|
+
end
|
27
|
+
|
28
|
+
# writes a .yamlr file HOME, merges with options if :dot is true
|
29
|
+
#
|
30
|
+
def self.dotfile(home = ENV['HOME'])
|
31
|
+
Yamlr::Writer.dotfile(Yamlr::Defaults.options, home)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# options
|
37
|
+
#
|
38
|
+
def self.options(options = {})
|
39
|
+
opt = Yamlr::Defaults.options.merge(Yamlr::Indicators.options.merge(options))
|
40
|
+
dot_opt = File.exists?(DOTFILE) ? Yamlr::Reader.read(DOTFILE, opt.merge({:symbolize_keys => true})) : nil
|
41
|
+
unless opt[:dot]
|
42
|
+
opt = opt.merge(dot_opt) if (dot_opt && dot_opt[:dot])
|
43
|
+
end
|
44
|
+
opt
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Yamlr
|
2
|
+
module Defaults
|
3
|
+
INT = true
|
4
|
+
INT_KEYS = false
|
5
|
+
INT_VALS = false
|
6
|
+
SYMBOLIZE = false
|
7
|
+
SYMBOLIZE_KEYS = false
|
8
|
+
SYMBOLIZE_VALS = false
|
9
|
+
SYM_STR = false
|
10
|
+
SYM_STR_KEYS = false
|
11
|
+
SYM_STR_VALS = false
|
12
|
+
AUTO_SYM = true
|
13
|
+
AUTO_SYM_KEYS = false
|
14
|
+
AUTO_SYM_VALS = false
|
15
|
+
AUTO_TRUE = true
|
16
|
+
AUTO_TRUE_KEYS = false
|
17
|
+
AUTO_TRUE_VALS = false
|
18
|
+
STRIP = true
|
19
|
+
STRIP_KEYS = false
|
20
|
+
STRIP_VALS = false
|
21
|
+
LIST = false
|
22
|
+
DOT = true
|
23
|
+
DOTFILE = "#{ENV['HOME']}/.yamlrc"
|
24
|
+
YAML = false
|
25
|
+
DOCS = false
|
26
|
+
|
27
|
+
def self.descriptions
|
28
|
+
{ "auto_sym" => "conv keys & vals: \":both\" => :both",
|
29
|
+
"auto_sym_keys" => "conv keys: \":key\" => :key",
|
30
|
+
"auto_sym_vals" => "conv vals: \":val\" => :val",
|
31
|
+
"auto_true" => "conv keys & vals: \"true\" => true",
|
32
|
+
"auto_true_keys" => "conv keys: \"true\" => true",
|
33
|
+
"auto_true_vals" => "conv vals: \"true\" => true",
|
34
|
+
"docs" => "doc separator first level hash nodes",
|
35
|
+
"dot" => "use dotfile if it exists",
|
36
|
+
"int" => "conv keys & vals: \"1\" => 1",
|
37
|
+
"int_keys" => "conv keys: \"1\" => 1",
|
38
|
+
"int_vals" => "conv vals: \"1\" => 1",
|
39
|
+
"list" => "return hash of addresses & comments",
|
40
|
+
"strip" => "strip keys & vals: \" both \" => \"both\"",
|
41
|
+
"strip_keys" => "strip keys: \" key \" => \"key\"",
|
42
|
+
"strip_vals" => "strip vals: \" val \" => \"val\"",
|
43
|
+
"sym_str" => "conv str (no int) k & v: \"b\" => :b",
|
44
|
+
"sym_str_keys" => "conv string keys(no int): \"key\" => :key",
|
45
|
+
"sym_str_vals" => "conv string vals(no int): \"val\" => :val",
|
46
|
+
"symbolize" => "force conv keys & vals: \"both\" => :both",
|
47
|
+
"symbolize_keys" => "force conv keys: \"key\" => :key",
|
48
|
+
"symbolize_vals" => "force conv vals: \"val\" => :val",
|
49
|
+
"yaml" => "write files with YAML type array syntax"}
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.options
|
53
|
+
{ :int => INT,
|
54
|
+
:int_keys => INT_KEYS,
|
55
|
+
:int_vals => INT_VALS,
|
56
|
+
:symbolize => SYMBOLIZE,
|
57
|
+
:symbolize_keys => SYMBOLIZE_KEYS,
|
58
|
+
:symbolize_vals => SYMBOLIZE_VALS,
|
59
|
+
:sym_str => SYM_STR,
|
60
|
+
:sym_str_keys => SYM_STR_KEYS,
|
61
|
+
:sym_str_vals => SYM_STR_VALS,
|
62
|
+
:auto_sym => AUTO_SYM,
|
63
|
+
:auto_sym_keys => AUTO_SYM_KEYS,
|
64
|
+
:auto_sym_vals => AUTO_SYM_VALS,
|
65
|
+
:auto_true => AUTO_TRUE,
|
66
|
+
:auto_true_keys => AUTO_TRUE_KEYS,
|
67
|
+
:auto_true_vals => AUTO_TRUE_VALS,
|
68
|
+
:strip => STRIP,
|
69
|
+
:strip_keys => STRIP_KEYS,
|
70
|
+
:strip_vals => STRIP_VALS,
|
71
|
+
:list => LIST,
|
72
|
+
:dot => DOT,
|
73
|
+
:dotfile => DOTFILE,
|
74
|
+
:yaml => YAML,
|
75
|
+
:docs => DOCS}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/yamlr/errors.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Yamlr
|
2
|
+
module Indicators
|
3
|
+
DOC_START = '---'
|
4
|
+
DOC_TERM = '...'
|
5
|
+
HASH = ':'
|
6
|
+
SYMBOL = ':'
|
7
|
+
ARRAY = '-'
|
8
|
+
COMMENT = '#'
|
9
|
+
LINE_END = "\n"
|
10
|
+
SPACE = "\s"
|
11
|
+
INDENT = 2
|
12
|
+
|
13
|
+
def self.options
|
14
|
+
{ :doc_start => DOC_START,
|
15
|
+
:doc_term => DOC_TERM,
|
16
|
+
:hash => HASH,
|
17
|
+
:symbol => SYMBOL,
|
18
|
+
:array => ARRAY,
|
19
|
+
:comment => COMMENT,
|
20
|
+
:line_end => LINE_END,
|
21
|
+
:space => SPACE,
|
22
|
+
:indent => INDENT }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/yamlr/reader.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'yamlr/reader/node'
|
2
|
+
require 'yamlr/reader/format'
|
3
|
+
require 'yamlr/reader/builder'
|
4
|
+
require 'yamlr/reader/parser'
|
5
|
+
|
6
|
+
module Yamlr
|
7
|
+
module Reader
|
8
|
+
class EmptyFileError < StandardError; end
|
9
|
+
class EmptyInputError < StandardError; end
|
10
|
+
class InvalidInputError < StandardError; end
|
11
|
+
#
|
12
|
+
# parses file or string into Ruby Array, or Hash
|
13
|
+
#
|
14
|
+
def self.read(input, options)
|
15
|
+
raise Yamlr::Reader::EmptyInputError if input.is_a?(String) && input.strip.empty?
|
16
|
+
raise Yamlr::Reader::InvalidInputError unless input.is_a?(String) or input.is_a?(File)
|
17
|
+
input = File.exists?(input) ? IO.readlines(input) : input.split("\n")
|
18
|
+
raise Yamlr::Reader::EmptyFileError if input.empty?
|
19
|
+
hash = {}
|
20
|
+
lineno = 0
|
21
|
+
input.each {|line|
|
22
|
+
parsed_hash = Yamlr::Reader::Parser.parse(line, options, (lineno += 1))
|
23
|
+
formatted_hash = Yamlr::Reader::Format.format(parsed_hash)
|
24
|
+
Yamlr::Reader::Builder.build(hash, formatted_hash)
|
25
|
+
}
|
26
|
+
hash.delete(:adr)
|
27
|
+
case
|
28
|
+
when options[:list] then hash
|
29
|
+
when !options[:list] then hash.delete(:lst) && (hash.length == 1) ? hash[1] : hash
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
module Yamlr
|
2
|
+
module Reader
|
3
|
+
module Builder
|
4
|
+
#
|
5
|
+
# Abbreviations:
|
6
|
+
# adr = address
|
7
|
+
# phs = parsed hash
|
8
|
+
# hsh = hash
|
9
|
+
# lst = list
|
10
|
+
# met = meta
|
11
|
+
# cur = current
|
12
|
+
# spc = spaces
|
13
|
+
# idt = indent
|
14
|
+
# idx = index
|
15
|
+
#
|
16
|
+
# dcs = doc_start
|
17
|
+
# dct = doc_term
|
18
|
+
# hpr = hsh_pair
|
19
|
+
# hky = hsh_key
|
20
|
+
# arr = array
|
21
|
+
# com = comment
|
22
|
+
# mal = malformed
|
23
|
+
# msg = message
|
24
|
+
# bla = blank
|
25
|
+
#
|
26
|
+
class RootNodeError < StandardError; end
|
27
|
+
|
28
|
+
##
|
29
|
+
# adds parsed_hash of line to hash
|
30
|
+
#
|
31
|
+
def self.build(hsh, phs)
|
32
|
+
add = false
|
33
|
+
upd = nil
|
34
|
+
msg = phs[:msg]
|
35
|
+
self.doc_new(hsh) if hsh.empty? && msg != "doc"
|
36
|
+
val = phs[:val]
|
37
|
+
lst = hsh[:lst]
|
38
|
+
|
39
|
+
unless [:com, :mal, :bla].include?(msg)
|
40
|
+
cur = self.cur(hsh)
|
41
|
+
key = phs[:key]
|
42
|
+
spc = phs[:spc]
|
43
|
+
idt = phs[:opt][:indent]
|
44
|
+
adr = hsh[:adr]
|
45
|
+
idx = self.index(spc, idt)
|
46
|
+
upd = self.update(adr, idx)
|
47
|
+
las = self.adr_obj(hsh, hsh[:adr])
|
48
|
+
add = true
|
49
|
+
end
|
50
|
+
|
51
|
+
case msg
|
52
|
+
when :dcs then self.doc_start(hsh)
|
53
|
+
when :dct then self.doc_term(hsh)
|
54
|
+
when :hpr then self.hsh_pair(las, key, val)
|
55
|
+
when :hky then self.hsh_key(las, adr, key)
|
56
|
+
when :bla then self.blank(lst)
|
57
|
+
when :arr
|
58
|
+
raise RootNodeError if cur.is_a?(Hash) && !cur.empty? && spc == 0
|
59
|
+
if las.is_a?(Hash) && las.empty?
|
60
|
+
self.adr_obj_to_array(hsh, hsh[:adr])
|
61
|
+
las = self.adr_obj(hsh, hsh[:adr])
|
62
|
+
end
|
63
|
+
self.arr_parse(las, adr, val, upd)
|
64
|
+
when :com then self.comment(lst, val)
|
65
|
+
when :mal then self.malformed(lst, val)
|
66
|
+
end
|
67
|
+
|
68
|
+
self.add_to_list(lst, adr) if add
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# sub-parses array message, and logic from update-method
|
73
|
+
#
|
74
|
+
def self.arr_parse(las, adr, val, upd)
|
75
|
+
case upd
|
76
|
+
when "eq" then self.array_val(las, val)
|
77
|
+
when "lt" then self.array_val(las, val)
|
78
|
+
when "gt" then self.array_new(las, adr, val)
|
79
|
+
else; raise "error"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# current hash, returns array of "doc"
|
84
|
+
#
|
85
|
+
def self.cur(hsh)
|
86
|
+
hsh[hsh.length - 2]
|
87
|
+
end
|
88
|
+
|
89
|
+
# address array to string usable in eval on root node
|
90
|
+
#
|
91
|
+
def self.to_adr(adr)
|
92
|
+
m = adr.map {|x|
|
93
|
+
case
|
94
|
+
when x.is_a?(Symbol) then "[:#{x}]"
|
95
|
+
when x.is_a?(String) then "['#{x}']"
|
96
|
+
when x.is_a?(Integer) then "[#{x}]"
|
97
|
+
end
|
98
|
+
}
|
99
|
+
m.join
|
100
|
+
end
|
101
|
+
|
102
|
+
# returns the actual object at an address in tree
|
103
|
+
#
|
104
|
+
def self.adr_obj(hsh, adr)
|
105
|
+
m = self.to_adr(adr)
|
106
|
+
eval("hsh#{m.to_s}")
|
107
|
+
end
|
108
|
+
|
109
|
+
# converts an object in tree to empty array
|
110
|
+
#
|
111
|
+
def self.adr_obj_to_array(hsh, adr)
|
112
|
+
m = self.to_adr(adr)
|
113
|
+
eval("hsh#{m.to_s} = []")
|
114
|
+
end
|
115
|
+
|
116
|
+
# calculates index based on spaces divided by indent unit
|
117
|
+
#
|
118
|
+
def self.index(spc, idt)
|
119
|
+
((spc % idt) != 0) ? 0 : spc / idt
|
120
|
+
end
|
121
|
+
|
122
|
+
# if indentation less than before, jump up tree, remove extra indices
|
123
|
+
#
|
124
|
+
def self.update(adr, idx)
|
125
|
+
ret = nil
|
126
|
+
len = (adr.length - 1)
|
127
|
+
if idx < len
|
128
|
+
# remove indices after current index
|
129
|
+
adr.replace(adr[0..idx])
|
130
|
+
ret = "lt"
|
131
|
+
elsif idx == len
|
132
|
+
ret = "eq"
|
133
|
+
elsif idx > len
|
134
|
+
ret = "gt"
|
135
|
+
end
|
136
|
+
ret
|
137
|
+
end
|
138
|
+
|
139
|
+
# create keypair for new doc
|
140
|
+
#
|
141
|
+
def self.doc_new(hsh)
|
142
|
+
hsh[:lst] ||= {}
|
143
|
+
hsh[:adr] ||= []
|
144
|
+
len = hsh.length - 1
|
145
|
+
hsh[len] = {}
|
146
|
+
hsh[:adr].clear
|
147
|
+
hsh[:adr] << len
|
148
|
+
end
|
149
|
+
|
150
|
+
# new array in tree, provides logic for last modified object
|
151
|
+
#
|
152
|
+
def self.array_new(las, adr, val)
|
153
|
+
case
|
154
|
+
when las.is_a?(Array) && las.empty?
|
155
|
+
x = [val]
|
156
|
+
las = x
|
157
|
+
adr << las.rindex(x)
|
158
|
+
when las.is_a?(Array) && las.last.is_a?(String) && las.last.empty?
|
159
|
+
x = [val]
|
160
|
+
las[-1] = [val]
|
161
|
+
adr << las.rindex(x)
|
162
|
+
when las.is_a?(Array)
|
163
|
+
x = [val]
|
164
|
+
las << x
|
165
|
+
adr << las.rindex(x)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# start document
|
170
|
+
#
|
171
|
+
def self.doc_start(hsh)
|
172
|
+
self.doc_new(hsh)
|
173
|
+
self.add_to_list(hsh[:lst], "#DOC_START")
|
174
|
+
end
|
175
|
+
|
176
|
+
# document terminate
|
177
|
+
#
|
178
|
+
def self.doc_term(hsh)
|
179
|
+
self.add_to_list(hsh[:lst], "#DOC_TERM")
|
180
|
+
end
|
181
|
+
|
182
|
+
# add val to array in tree
|
183
|
+
#
|
184
|
+
def self.array_val(las, val)
|
185
|
+
case
|
186
|
+
# when x is a hash, it's already addressed
|
187
|
+
when las.is_a?(Array)
|
188
|
+
las << val
|
189
|
+
else
|
190
|
+
raise las.inspect
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# add hashkey to tree
|
195
|
+
#
|
196
|
+
def self.hsh_key(las, adr, key)
|
197
|
+
case
|
198
|
+
when las.is_a?(Hash)
|
199
|
+
las[key] = {}
|
200
|
+
when las.is_a?(Array)
|
201
|
+
x = {key => {}}
|
202
|
+
las << x
|
203
|
+
adr << las.rindex(x)
|
204
|
+
end
|
205
|
+
adr << key
|
206
|
+
end
|
207
|
+
|
208
|
+
# add hashpair to tree
|
209
|
+
#
|
210
|
+
def self.hsh_pair(las, key, val)
|
211
|
+
case
|
212
|
+
when las.is_a?(Array)
|
213
|
+
x = {key => val}
|
214
|
+
las << x
|
215
|
+
when las.is_a?(Hash)
|
216
|
+
las[key] = val
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# list stores hsh addresses of lines, comments, etc.
|
221
|
+
#
|
222
|
+
def self.add_to_list(lst, adr)
|
223
|
+
case adr.class.to_s
|
224
|
+
when "String" then x = adr
|
225
|
+
when "Array" then x = adr.join(",")
|
226
|
+
end
|
227
|
+
lst[lst.length + 1] = x
|
228
|
+
end
|
229
|
+
|
230
|
+
# add blank to list
|
231
|
+
#
|
232
|
+
def self.blank(lst)
|
233
|
+
self.add_to_list(lst, "#BLANK")
|
234
|
+
end
|
235
|
+
|
236
|
+
# add comment to list
|
237
|
+
#
|
238
|
+
def self.comment(lst, val)
|
239
|
+
lst[lst.length + 1] = "#COMMENT: #{val}"
|
240
|
+
end
|
241
|
+
|
242
|
+
# add malformed to list
|
243
|
+
#
|
244
|
+
def self.malformed(lst, val)
|
245
|
+
lst[lst.length + 1] = "#MALFORMED: #{val}"
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|