lector 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []