lector 0.0.1 → 0.0.2
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/.travis.yml +12 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +2 -0
- data/README.md +13 -1
- data/lib/lector/reader.citrus +12 -4
- data/lib/lector/types.rb +8 -0
- data/lib/lector/version.rb +1 -1
- data/lib/lector.rb +4 -3
- data/spec/lector/reader_spec.rb +51 -44
- metadata +2 -1
data/.travis.yml
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
|
5
|
+
# Only build master branch
|
6
|
+
branches:
|
7
|
+
only:
|
8
|
+
- master
|
9
|
+
|
10
|
+
# To stop Travis from running tests for a new commit,
|
11
|
+
# add the following to your commit message: [ci skip]
|
12
|
+
# You should add this when you edit documentation or comments, etc.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -24,6 +24,7 @@ GEM
|
|
24
24
|
method_source (~> 0.6.7)
|
25
25
|
ruby_parser (>= 2.3.1)
|
26
26
|
slop (~> 2.1.0)
|
27
|
+
rake (0.9.2.2)
|
27
28
|
rspec (2.7.0)
|
28
29
|
rspec-core (~> 2.7.0)
|
29
30
|
rspec-expectations (~> 2.7.0)
|
@@ -50,5 +51,6 @@ DEPENDENCIES
|
|
50
51
|
guard-rspec
|
51
52
|
lector!
|
52
53
|
pry
|
54
|
+
rake
|
53
55
|
rspec
|
54
56
|
simplecov
|
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
|
-
`lector` reads Ruby data as a string or from a file without evaluating the code it reads.
|
1
|
+
`lector` reads Ruby data as a string or from a file without evaluating the code it reads. [](http://travis-ci.org/alandipert/lector)
|
2
2
|
|
3
3
|
# Usage
|
4
4
|
|
5
|
+
## Reading Strings
|
5
6
|
```
|
6
7
|
> require 'lector'
|
7
8
|
=> true
|
@@ -9,6 +10,17 @@
|
|
9
10
|
=> {:x=>11, :pants?=>false}
|
10
11
|
```
|
11
12
|
|
13
|
+
## Read-Eval
|
14
|
+
```
|
15
|
+
# read-eval is off by default:
|
16
|
+
> Lector::read_s("{three: #='1+2'}")
|
17
|
+
=> {:three=>nil}
|
18
|
+
|
19
|
+
# but you can turn it on...
|
20
|
+
> Lector::read_s("{three: #='1+2'}", :read_eval => true)
|
21
|
+
=> {:three=>3}
|
22
|
+
```
|
23
|
+
|
12
24
|
Please see the
|
13
25
|
[tests](https://github.com/alandipert/lector/tree/master/spec/lector)
|
14
26
|
for more usage examples.
|
data/lib/lector/reader.citrus
CHANGED
@@ -9,7 +9,7 @@ grammar Lector::RubyParse
|
|
9
9
|
end
|
10
10
|
|
11
11
|
rule literal
|
12
|
-
nil | boolean | string | symbol | hashkey | number
|
12
|
+
nil | boolean | string | code | symbol | hashkey | number
|
13
13
|
end
|
14
14
|
|
15
15
|
rule nil
|
@@ -21,11 +21,19 @@ grammar Lector::RubyParse
|
|
21
21
|
end
|
22
22
|
|
23
23
|
rule string
|
24
|
-
|
24
|
+
single_quoted_string | double_quoted_string
|
25
25
|
end
|
26
26
|
|
27
|
-
rule
|
28
|
-
(/[^"\\]/ | /\\./)
|
27
|
+
rule double_quoted_string
|
28
|
+
("\"" content:(/[^"\\]/ | /\\./)* "\"") <Lector::Types::String>
|
29
|
+
end
|
30
|
+
|
31
|
+
rule single_quoted_string
|
32
|
+
("'" content:(/[^'\\]/ | /\\./)* "'") <Lector::Types::String>
|
33
|
+
end
|
34
|
+
|
35
|
+
rule code
|
36
|
+
("#=" code:string) <Lector::Types::Code>
|
29
37
|
end
|
30
38
|
|
31
39
|
rule symbol
|
data/lib/lector/types.rb
CHANGED
@@ -11,6 +11,14 @@ module Lector
|
|
11
11
|
module HashKey; def val; to_sym; end; end
|
12
12
|
module String; def val; captures[:content].first.gsub(/\\\"/,"\""); end; end
|
13
13
|
|
14
|
+
module Code
|
15
|
+
def val
|
16
|
+
if $_LECTOR_READ_EVAL
|
17
|
+
eval(code.to_s.slice(3..-2))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
14
22
|
module Array
|
15
23
|
def val
|
16
24
|
captures[:form].map(&:val)
|
data/lib/lector/version.rb
CHANGED
data/lib/lector.rb
CHANGED
@@ -7,10 +7,11 @@ end
|
|
7
7
|
|
8
8
|
module Lector
|
9
9
|
module RubyParse; end
|
10
|
-
def self.read_s(string)
|
10
|
+
def self.read_s(string, opts = {})
|
11
|
+
$_LECTOR_READ_EVAL = opts[:read_eval]
|
11
12
|
Lector::RubyParse::parse(string).val
|
12
13
|
end
|
13
|
-
def self.read_file(file)
|
14
|
-
|
14
|
+
def self.read_file(file, opts = {})
|
15
|
+
read_s(File.read(file), opts)
|
15
16
|
end
|
16
17
|
end
|
data/spec/lector/reader_spec.rb
CHANGED
@@ -2,107 +2,114 @@ require File.join(File.dirname(__FILE__), *%w[.. spec_helper.rb])
|
|
2
2
|
require 'pry'
|
3
3
|
require 'tempfile'
|
4
4
|
|
5
|
-
def read_s(string)
|
6
|
-
Lector::read_s(string)
|
7
|
-
end
|
8
|
-
|
9
|
-
def read_file(file)
|
10
|
-
Lector::read_file(file)
|
11
|
-
end
|
12
|
-
|
13
5
|
describe Lector do
|
14
6
|
context 'reading strings' do
|
15
7
|
it 'parses integers' do
|
16
|
-
read_s("+42").should == 42
|
17
|
-
read_s("-42").should == -42
|
18
|
-
read_s("42").should == 42
|
19
|
-
read_s("-42").should == -42
|
20
|
-
read_s("-0").should == 0
|
21
|
-
read_s("+0").should == 0
|
8
|
+
Lector::read_s("+42").should == 42
|
9
|
+
Lector::read_s("-42").should == -42
|
10
|
+
Lector::read_s("42").should == 42
|
11
|
+
Lector::read_s("-42").should == -42
|
12
|
+
Lector::read_s("-0").should == 0
|
13
|
+
Lector::read_s("+0").should == 0
|
22
14
|
end
|
23
15
|
|
24
16
|
it "parses hex integers" do
|
25
|
-
read_s("0xF").should == 15
|
26
|
-
read_s("+0xF").should == 15
|
27
|
-
read_s("-0xF").should == -15
|
17
|
+
Lector::read_s("0xF").should == 15
|
18
|
+
Lector::read_s("+0xF").should == 15
|
19
|
+
Lector::read_s("-0xF").should == -15
|
28
20
|
end
|
29
21
|
|
30
22
|
it "parses floating point numbers" do
|
31
|
-
read_s("1.1").should == 1.1
|
32
|
-
read_s("-1.1").should == -1.1
|
33
|
-
read_s("-1.21e10").should == -12_100_000_000.0
|
34
|
-
read_s("+1.21e10").should == 12_100_000_000.0
|
35
|
-
read_s("1e4").should == 10_000
|
23
|
+
Lector::read_s("1.1").should == 1.1
|
24
|
+
Lector::read_s("-1.1").should == -1.1
|
25
|
+
Lector::read_s("-1.21e10").should == -12_100_000_000.0
|
26
|
+
Lector::read_s("+1.21e10").should == 12_100_000_000.0
|
27
|
+
Lector::read_s("1e4").should == 10_000
|
36
28
|
end
|
37
29
|
|
38
30
|
it "parses true and false" do
|
39
|
-
read_s("true").should == true
|
40
|
-
read_s("false").should == false
|
31
|
+
Lector::read_s("true").should == true
|
32
|
+
Lector::read_s("false").should == false
|
41
33
|
end
|
42
34
|
|
43
35
|
it "parses nil" do
|
44
|
-
read_s("nil").should == nil
|
36
|
+
Lector::read_s("nil").should == nil
|
45
37
|
end
|
46
38
|
|
47
39
|
it 'parses symbols' do
|
48
|
-
read_s(":sym").should == :sym
|
49
|
-
read_s(':"blah"').should == :blah
|
50
|
-
read_s(':"blah blah"').should == :"blah blah"
|
40
|
+
Lector::read_s(":sym").should == :sym
|
41
|
+
Lector::read_s(':"blah"').should == :blah
|
42
|
+
Lector::read_s(':"blah blah"').should == :"blah blah"
|
43
|
+
Lector::read_s(":'foo foo'").should == :"foo foo"
|
51
44
|
end
|
52
45
|
|
53
46
|
it 'parses arrays of single elements' do
|
54
|
-
read_s('[42]').should == [42]
|
47
|
+
Lector::read_s('[42]').should == [42]
|
55
48
|
end
|
56
49
|
|
57
50
|
it 'ignores whitespace' do
|
58
|
-
read_s("[ 42 ]").should == [42]
|
51
|
+
Lector::read_s("[ 42 ]").should == [42]
|
59
52
|
end
|
60
53
|
|
61
54
|
it 'parses arrays of multiple elements' do
|
62
|
-
read_s("[42, -1]").should == [42, -1]
|
55
|
+
Lector::read_s("[42, -1]").should == [42, -1]
|
63
56
|
end
|
64
57
|
|
65
58
|
it 'parses hashes' do
|
66
|
-
read_s("{a: 7, b: 6}").should == {:a => 7, :b => 6}
|
67
|
-
read_s("{b: 6}").should == {:b => 6}
|
68
|
-
read_s("{:a => 7, :b => 6}").should == {:a => 7, :b => 6}
|
69
|
-
read_s("{:a => 7, b: 6}").should == {:a => 7, :b => 6}
|
59
|
+
Lector::read_s("{a: 7, b: 6}").should == {:a => 7, :b => 6}
|
60
|
+
Lector::read_s("{b: 6}").should == {:b => 6}
|
61
|
+
Lector::read_s("{:a => 7, :b => 6}").should == {:a => 7, :b => 6}
|
62
|
+
Lector::read_s("{:a => 7, b: 6}").should == {:a => 7, :b => 6}
|
70
63
|
end
|
71
64
|
|
72
65
|
it 'parses nested collections' do
|
73
|
-
read_s("[[1,2], 3, 4]").should == [[1, 2], 3, 4]
|
66
|
+
Lector::read_s("[[1,2], 3, 4]").should == [[1, 2], 3, 4]
|
74
67
|
end
|
75
68
|
|
76
69
|
it 'has no problem with hashes of arrays' do
|
77
|
-
read_s("{a: [1, 2], b: [3, 4]}").should == {:a => [1, 2], :b => [3, 4]}
|
78
|
-
read_s("{:a => [1, 2], :b => [3, 4]}").should == {:a => [1, 2], :b => [3, 4]}
|
70
|
+
Lector::read_s("{a: [1, 2], b: [3, 4]}").should == {:a => [1, 2], :b => [3, 4]}
|
71
|
+
Lector::read_s("{:a => [1, 2], :b => [3, 4]}").should == {:a => [1, 2], :b => [3, 4]}
|
79
72
|
end
|
80
73
|
|
81
74
|
it 'copes when data is surrounded by whitespace' do
|
82
|
-
read_s("
|
75
|
+
Lector::read_s("
|
83
76
|
{a: 7, b: 6} ").should == {:a => 7, :b => 6}
|
84
77
|
end
|
85
78
|
|
86
|
-
it 'reads strings' do
|
87
|
-
read_s('"a string by any other name is just as tangly"').should == 'a string by any other name is just as tangly'
|
79
|
+
it 'reads double-quoted strings' do
|
80
|
+
Lector::read_s('"a string by any other name is just as tangly"').should == 'a string by any other name is just as tangly'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'reads single-quoted strings' do
|
84
|
+
Lector::read_s("'i only have single quotes'").should == 'i only have single quotes'
|
88
85
|
end
|
89
86
|
|
90
87
|
it 'reads strings with escaped quotes' do
|
91
|
-
read_s('"a string with an \"escaped quote\""').should == 'a string with an "escaped quote"'
|
88
|
+
Lector::read_s('"a string with an \"escaped quote\""').should == 'a string with an "escaped quote"'
|
92
89
|
end
|
93
90
|
|
94
91
|
it 'preserves other escaped characters' do
|
95
|
-
read_s('"a string with a\nnewline"').should == 'a string with a\nnewline'
|
92
|
+
Lector::read_s('"a string with a\nnewline"').should == 'a string with a\nnewline'
|
96
93
|
end
|
97
94
|
end
|
98
95
|
|
96
|
+
context 'read-evaling' do
|
97
|
+
it "shouldn't eval the code" do
|
98
|
+
Lector::read_s("#='1+2'").should == nil
|
99
|
+
end
|
100
|
+
it "should eval the code" do
|
101
|
+
Lector::read_s("#='1+2'", :read_eval => true).should == 3
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
99
106
|
context 'reading files' do
|
100
107
|
it 'should be able to round-trip data to file' do
|
101
108
|
hsh = {:a => [1, 2], nil => false, :b => [3, 4], blah: [1.2, {:x => 20}]}
|
102
109
|
Tempfile.new('lector').tap do |f|
|
103
110
|
f.write(hsh.to_s)
|
104
111
|
f.rewind
|
105
|
-
read_file(f).should == hsh
|
112
|
+
Lector::read_file(f).should == hsh
|
106
113
|
end
|
107
114
|
end
|
108
115
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lector
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- .document
|
120
120
|
- .gitignore
|
121
121
|
- .rvmrc
|
122
|
+
- .travis.yml
|
122
123
|
- Gemfile
|
123
124
|
- Gemfile.lock
|
124
125
|
- Guardfile
|