lector 0.0.1

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/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.gitignore ADDED
@@ -0,0 +1,49 @@
1
+ # rcov generated
2
+ coverage
3
+
4
+ # rdoc generated
5
+ rdoc
6
+
7
+ # yard generated
8
+ doc
9
+ .yardoc
10
+
11
+ # bundler
12
+ .bundle
13
+
14
+ # jeweler generated
15
+ pkg
16
+ *.gem
17
+
18
+ # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
19
+ #
20
+ # * Create a file at ~/.gitignore
21
+ # * Include files you want ignored
22
+ # * Run: git config --global core.excludesfile ~/.gitignore
23
+ #
24
+ # After doing this, these files will be ignored in all your git projects,
25
+ # saving you from having to 'pollute' every project you touch with them
26
+ #
27
+ # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
28
+ #
29
+ # For MacOS:
30
+ #
31
+ .DS_Store
32
+
33
+ # For TextMate
34
+ #*.tmproj
35
+ #tmtags
36
+
37
+ # For emacs:
38
+ #*~
39
+ #\#*
40
+ #.\#*
41
+
42
+ # For vim:
43
+ #*.swp
44
+
45
+ # For redcar:
46
+ #.redcar
47
+
48
+ # For rubinius:
49
+ #*.rbc
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3@lector
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,54 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ lector (0.0.1)
5
+ citrus
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ citrus (2.4.1)
11
+ coderay (0.9.8)
12
+ diff-lcs (1.1.3)
13
+ ffi (1.0.11)
14
+ guard (1.0.1)
15
+ ffi (>= 0.5.0)
16
+ thor (~> 0.14.6)
17
+ guard-rspec (0.5.8)
18
+ guard (>= 0.8.4)
19
+ method_source (0.6.7)
20
+ ruby_parser (>= 2.3.1)
21
+ multi_json (1.0.3)
22
+ pry (0.9.7.4)
23
+ coderay (~> 0.9.8)
24
+ method_source (~> 0.6.7)
25
+ ruby_parser (>= 2.3.1)
26
+ slop (~> 2.1.0)
27
+ rspec (2.7.0)
28
+ rspec-core (~> 2.7.0)
29
+ rspec-expectations (~> 2.7.0)
30
+ rspec-mocks (~> 2.7.0)
31
+ rspec-core (2.7.1)
32
+ rspec-expectations (2.7.0)
33
+ diff-lcs (~> 1.1.2)
34
+ rspec-mocks (2.7.0)
35
+ ruby_parser (2.3.1)
36
+ sexp_processor (~> 3.0)
37
+ sexp_processor (3.0.8)
38
+ simplecov (0.5.4)
39
+ multi_json (~> 1.0.3)
40
+ simplecov-html (~> 0.5.3)
41
+ simplecov-html (0.5.3)
42
+ slop (2.1.0)
43
+ thor (0.14.6)
44
+
45
+ PLATFORMS
46
+ ruby
47
+
48
+ DEPENDENCIES
49
+ guard
50
+ guard-rspec
51
+ lector!
52
+ pry
53
+ rspec
54
+ simplecov
data/Guardfile ADDED
@@ -0,0 +1,13 @@
1
+ if RbConfig::CONFIG['host_os'] =~ /linux/
2
+ notification :notifysend
3
+ end
4
+
5
+ guard 'rspec',
6
+ version: 2,
7
+ cli: '--format documentation',
8
+ all_on_start: false,
9
+ all_after_pass: false do
10
+ watch(%r{^spec/.+_spec\.rb$})
11
+ watch(%r{^lib/(.+)\.(rb|citrus)$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
12
+ watch('spec/spec_helper.rb') { "spec" }
13
+ end
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ `lector` reads Ruby data as a string or from a file without evaluating the code it reads.
2
+
3
+ # Usage
4
+
5
+ ```
6
+ > require 'lector'
7
+ => true
8
+ > Lector::read_s("{x: 11, :pants? => false}")
9
+ => {:x=>11, :pants?=>false}
10
+ ```
11
+
12
+ Please see the
13
+ [tests](https://github.com/alandipert/lector/tree/master/spec/lector)
14
+ for more usage examples.
15
+
16
+ # Rationale
17
+
18
+ Ruby's literal support for hashes, arrays, keywords, numbers, and
19
+ strings makes Ruby data slightly more expressive than JSON and
20
+ arguably as expressive as YAML.
21
+
22
+ Ruby could be a decent format for representing things like markup or
23
+ configuration data. This library allows you to digest Ruby data
24
+ strings and files without having to worry if arbitrary code will
25
+ execute.
26
+
27
+ # Thanks
28
+
29
+ This library started as a fork of Michael Fogus and Alex Redington's
30
+ [clj.rb](https://github.com/fogus/clj.rb), a library for parsing
31
+ [Clojure](http://clojure.org) data from Ruby. A big thanks to them
32
+ for getting this party started.
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ require "rspec/core/rake_task"
4
+ require 'rake'
5
+
6
+ desc "Run all specs"
7
+ RSpec::Core::RakeTask.new(:spec) do |t|
8
+ t.pattern = "spec/**/*_spec.rb"
9
+ t.ruby_opts = '-Ilib -Ispec -I.'
10
+ t.rspec_opts = '--color'
11
+ end
12
+
13
+ task :default => :spec
data/lector.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "lector/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "lector"
7
+ s.version = Lector::VERSION
8
+ s.authors = ["Alan Dipert", "Michael Fogus", "Alex Redington"]
9
+ s.email = ["alan@dipert.org"]
10
+ s.homepage = "http://github.com/alandipert/lector"
11
+ s.summary = %q{A Ruby data reader.}
12
+ s.description = %q{lector parses Ruby data into Ruby data structures.}
13
+
14
+ s.rubyforge_project = "lector"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ s.add_development_dependency 'pry'
23
+ s.add_development_dependency 'rspec'
24
+ s.add_development_dependency 'guard'
25
+ s.add_development_dependency 'guard-rspec'
26
+ s.add_development_dependency 'simplecov'
27
+ s.add_runtime_dependency 'citrus'
28
+ end
@@ -0,0 +1,88 @@
1
+ grammar Lector::RubyParse
2
+
3
+ rule ruby_data
4
+ (space* form space*) <Lector::Types::Data>
5
+ end
6
+
7
+ rule form
8
+ array | hash | literal
9
+ end
10
+
11
+ rule literal
12
+ nil | boolean | string | symbol | hashkey | number
13
+ end
14
+
15
+ rule nil
16
+ "nil" <Lector::Types::Nil>
17
+ end
18
+
19
+ rule boolean
20
+ ("true" | "false") <Lector::Types::Boolean>
21
+ end
22
+
23
+ rule string
24
+ ("\"" content:string_content* "\"") <Lector::Types::String>
25
+ end
26
+
27
+ rule string_content
28
+ (/[^"\\]/ | /\\./)
29
+ end
30
+
31
+ rule symbol
32
+ simple_symbol | string_symbol
33
+ end
34
+
35
+ rule simple_symbol
36
+ (":" symbol_content) <Lector::Types::SimpleSymbol>
37
+ end
38
+
39
+ rule symbol_content
40
+ /[a-zA-Z!_][a-zA-Z0-9_]*[\?!]?/
41
+ end
42
+
43
+ rule string_symbol
44
+ (":" string) <Lector::Types::StringSymbol>
45
+ end
46
+
47
+ rule number
48
+ hex_integer | float | integer
49
+ end
50
+
51
+ rule hex_integer
52
+ /([-+]?)0[xX]([0-9A-Fa-f]+)?/ <Lector::Types::HexInteger>
53
+ end
54
+
55
+ rule float
56
+ ((number:/[-+]?[0-9]+\.[0-9]*(?:[eE][-+]?[0-9]+)?/)
57
+ | (number:/[-+]?[0-9][eE][-+]?[0-9]+/)) <Lector::Types::Float>
58
+ end
59
+
60
+ rule integer
61
+ /([-+]?0)|([-+]?[1-9]\d*)?/ <Lector::Types::Integer>
62
+ end
63
+
64
+ rule array
65
+ #TODO: Spurious commas should be parse errors.
66
+ ('['
67
+ ((space* form space* ',')* (space* form space*))
68
+ ']') <Lector::Types::Array>
69
+ end
70
+
71
+ rule hash
72
+ #TODO: Spurious commas should be parse errors.
73
+ ('{'
74
+ (((space* form space* '=>' space* form space* ',') |
75
+ (space* form ':' space* form space* ','))*
76
+ ((space* form space* '=>' space* form space*) |
77
+ (space* form ':' space* form space*)))
78
+ '}') <Lector::Types::Hash>
79
+ end
80
+
81
+ rule hashkey
82
+ #TODO: Kludge - this shouldn't be a standalone terminal.
83
+ symbol_content <Lector::Types::HashKey>
84
+ end
85
+
86
+ rule space [ \t\n\r] end
87
+
88
+ end
@@ -0,0 +1,31 @@
1
+ module Lector
2
+ module Types
3
+ module Data; def val; form.val; end; end
4
+ module Boolean; def val; to_s == "true"; end; end
5
+ module Nil; def val; nil; end; end
6
+ module Integer; def val; to_i; end; end
7
+ module HexInteger; def val; to_i 16; end; end
8
+ module Float; def val; to_f; end; end
9
+ module SimpleSymbol; def val; slice(1..-1).to_sym; end; end
10
+ module StringSymbol; def val; slice(2..-2).to_sym; end; end
11
+ module HashKey; def val; to_sym; end; end
12
+ module String; def val; captures[:content].first.gsub(/\\\"/,"\""); end; end
13
+
14
+ module Array
15
+ def val
16
+ captures[:form].map(&:val)
17
+ end
18
+ end
19
+
20
+ module Hash
21
+ def val
22
+ ruby_val = {}
23
+ captures[:form].each_slice(2) do |slice|
24
+ key,value = slice
25
+ ruby_val[key.val] = value.val
26
+ end
27
+ ruby_val
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module Lector
2
+ VERSION = "0.0.1"
3
+ end
data/lib/lector.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'citrus'
2
+ require 'lector/types'
3
+
4
+ module Lector
5
+ Citrus.load('lib/lector/reader', :force => true)
6
+ end
7
+
8
+ module Lector
9
+ module RubyParse; end
10
+ def self.read_s(string)
11
+ Lector::RubyParse::parse(string).val
12
+ end
13
+ def self.read_file(file)
14
+ Lector::RubyParse::parse(File.read(file)).val
15
+ end
16
+ end
@@ -0,0 +1,109 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. spec_helper.rb])
2
+ require 'pry'
3
+ require 'tempfile'
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
+ describe Lector do
14
+ context 'reading strings' do
15
+ 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
22
+ end
23
+
24
+ it "parses hex integers" do
25
+ read_s("0xF").should == 15
26
+ read_s("+0xF").should == 15
27
+ read_s("-0xF").should == -15
28
+ end
29
+
30
+ 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
36
+ end
37
+
38
+ it "parses true and false" do
39
+ read_s("true").should == true
40
+ read_s("false").should == false
41
+ end
42
+
43
+ it "parses nil" do
44
+ read_s("nil").should == nil
45
+ end
46
+
47
+ it 'parses symbols' do
48
+ read_s(":sym").should == :sym
49
+ read_s(':"blah"').should == :blah
50
+ read_s(':"blah blah"').should == :"blah blah"
51
+ end
52
+
53
+ it 'parses arrays of single elements' do
54
+ read_s('[42]').should == [42]
55
+ end
56
+
57
+ it 'ignores whitespace' do
58
+ read_s("[ 42 ]").should == [42]
59
+ end
60
+
61
+ it 'parses arrays of multiple elements' do
62
+ read_s("[42, -1]").should == [42, -1]
63
+ end
64
+
65
+ 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}
70
+ end
71
+
72
+ it 'parses nested collections' do
73
+ read_s("[[1,2], 3, 4]").should == [[1, 2], 3, 4]
74
+ end
75
+
76
+ 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]}
79
+ end
80
+
81
+ it 'copes when data is surrounded by whitespace' do
82
+ read_s("
83
+ {a: 7, b: 6} ").should == {:a => 7, :b => 6}
84
+ end
85
+
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'
88
+ end
89
+
90
+ it 'reads strings with escaped quotes' do
91
+ read_s('"a string with an \"escaped quote\""').should == 'a string with an "escaped quote"'
92
+ end
93
+
94
+ it 'preserves other escaped characters' do
95
+ read_s('"a string with a\nnewline"').should == 'a string with a\nnewline'
96
+ end
97
+ end
98
+
99
+ context 'reading files' do
100
+ it 'should be able to round-trip data to file' do
101
+ hsh = {:a => [1, 2], nil => false, :b => [3, 4], blah: [1.2, {:x => 20}]}
102
+ Tempfile.new('lector').tap do |f|
103
+ f.write(hsh.to_s)
104
+ f.rewind
105
+ read_file(f).should == hsh
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,7 @@
1
+ require File.join(File.dirname(__FILE__), *%w[.. lib lector])
2
+
3
+ RSpec.configure do |config|
4
+ config.filter_run :focused => true
5
+ config.alias_example_to :fit, :focused => true
6
+ config.run_all_when_everything_filtered = true
7
+ end
metadata ADDED
@@ -0,0 +1,158 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: lector
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Alan Dipert
9
+ - Michael Fogus
10
+ - Alex Redington
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2012-05-04 00:00:00.000000000 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: pry
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :development
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: rspec
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ! '>='
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ - !ruby/object:Gem::Dependency
49
+ name: guard
50
+ requirement: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ - !ruby/object:Gem::Dependency
65
+ name: guard-rspec
66
+ requirement: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ type: :development
73
+ prerelease: false
74
+ version_requirements: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ - !ruby/object:Gem::Dependency
81
+ name: simplecov
82
+ requirement: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: citrus
98
+ requirement: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ description: lector parses Ruby data into Ruby data structures.
113
+ email:
114
+ - alan@dipert.org
115
+ executables: []
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - .document
120
+ - .gitignore
121
+ - .rvmrc
122
+ - Gemfile
123
+ - Gemfile.lock
124
+ - Guardfile
125
+ - README.md
126
+ - Rakefile
127
+ - lector.gemspec
128
+ - lib/lector.rb
129
+ - lib/lector/reader.citrus
130
+ - lib/lector/types.rb
131
+ - lib/lector/version.rb
132
+ - spec/lector/reader_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: http://github.com/alandipert/lector
135
+ licenses: []
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ none: false
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ required_rubygems_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project: lector
154
+ rubygems_version: 1.8.24
155
+ signing_key:
156
+ specification_version: 3
157
+ summary: A Ruby data reader.
158
+ test_files: []