sxp 0.0.14 → 0.1.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/AUTHORS CHANGED
@@ -1 +1 @@
1
- * Arto Bendiken <arto.bendiken@gmail.com>
1
+ * Arto Bendiken <arto@bendiken.net>
data/README CHANGED
@@ -1,21 +1,18 @@
1
- SXP.rb: S-Expressions for Ruby
2
- ==============================
1
+ #SXP.rb: S-Expressions for Ruby
3
2
 
4
3
  This is a Ruby implementation of a universal [S-expression][] parser.
5
4
 
6
5
  * <http://sxp.rubyforge.org/>
7
6
  * <http://github.com/bendiken/sxp-ruby>
8
7
 
9
- Features
10
- --------
8
+ ##Features
11
9
 
12
10
  * Parses S-expressions in universal, [Scheme][], [Common Lisp][], or
13
11
  [SPARQL][] syntax.
14
12
  * Adds a `#to_sxp` method to Ruby objects.
15
13
  * Compatible with Ruby 1.8.7+, Ruby 1.9.x, and JRuby 1.4/1.5.
16
14
 
17
- Examples
18
- --------
15
+ ##Examples
19
16
 
20
17
  require 'sxp'
21
18
 
@@ -49,8 +46,11 @@ Examples
49
46
 
50
47
  SXP::Reader::SPARQL.read %q((base <http://ar.to/>)) #=> [:base, RDF::URI('http://ar.to/')]
51
48
 
52
- Documentation
53
- -------------
49
+ ### Writing an SXP with formatting
50
+
51
+ SXP::Generator.print([:and, true, false]) #=> (and #t #f)
52
+
53
+ ##Documentation
54
54
 
55
55
  * <http://sxp.rubyforge.org/>
56
56
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.14
1
+ 0.1.0
data/lib/sxp.rb CHANGED
@@ -39,8 +39,13 @@ module SXP
39
39
  ##
40
40
  # Reads all S-expressions from the given input files.
41
41
  #
42
- # @param [Enumerable<String>] filenames
43
- # @param [Hash{Symbol => Object}] options
42
+ # @overload read_files(*filenames)
43
+ # @param [Enumerable<String>] filenames
44
+ #
45
+ # @overload read_files(*filenames, options)
46
+ # @param [Enumerable<String>] filenames
47
+ # @param [Hash{Symbol => Object}] options
48
+ #
44
49
  # @return [Enumerable<Object>]
45
50
  def self.read_files(*filenames)
46
51
  Reader::Scheme.read_files(*filenames)
@@ -75,6 +80,15 @@ module SXP
75
80
  def self.read(input, options = {})
76
81
  Reader::Scheme.read(input, options)
77
82
  end
83
+
84
+ ##
85
+ # Write an internal S-Expression as a formatted SXP
86
+ #
87
+ # @param[Array<Object>] sxp
88
+ # @param[#write] output
89
+ def self.write(sxp, output = STDOUT)
90
+ Generator.write(output, sxp)
91
+ end
78
92
 
79
93
  class << self
80
94
  alias_method :parse, :read
data/lib/sxp/generator.rb CHANGED
@@ -1,16 +1,102 @@
1
1
  module SXP
2
2
  ##
3
3
  # An S-expression generator.
4
+ #
5
+ # Takes an object and pretty-prints it using reasonable indentation rules
4
6
  class Generator
5
7
  ##
8
+ # A basic block containing constituent
9
+ # objects, either blocks or strings.
10
+ class Block
11
+ BLOCK_MIN_LENGTH = 40
12
+
13
+ # @attr [Integer] amount of indent applied to this block
14
+ attr_reader :indent
15
+
16
+ ##
17
+ # @param [Object] obj
18
+ def initialize(obj, indent)
19
+ @indent = indent
20
+ @elements = []
21
+ if obj.is_a?(Array)
22
+ obj.compact.each {|o| @elements << Block.new(o, indent + 1)}
23
+ else
24
+ @elements = obj
25
+ end
26
+ end
27
+
28
+ ##
29
+ # Agregate length over each element accounting for spaces
30
+ #
31
+ # @return [Integer]
32
+ # If indent is not not nil, returns zero
33
+ def length
34
+ if @elements.is_a?(Array)
35
+ @elements.map(&:length).inject(:+).to_i + @elements.length - 1
36
+ else
37
+ @elements.to_sxp.length
38
+ end
39
+ end
40
+
41
+ ##
42
+ # Turn block into a string in S-expression form
43
+ # This should only be called on a block when
44
+ # no indentation is to be applied
45
+ # @return [String]
46
+ def to_sxp
47
+ @elements.to_sxp
48
+ end
49
+
50
+ ##
51
+ # Determins if this block is an SXP, or not
52
+ # @return [Boolean]
53
+ def sxp?
54
+ @elements.is_a?(Array)
55
+ end
56
+
57
+ ##
58
+ # Output block applying indent recursively
59
+ # @param [#write] io
60
+ def write(io)
61
+ # Output individual block elements on separate lines
62
+ if sxp? && length > BLOCK_MIN_LENGTH
63
+ io.write(do_indent + '(')
64
+ first, *elems = @elements
65
+ unless first.sxp?
66
+ # It's atomic, write out after paren
67
+ io.puts(first.to_sxp)
68
+ else
69
+ io.write("\n")
70
+ elems.unshift(first)
71
+ end
72
+ elems.each do |e|
73
+ e.write(io)
74
+ end
75
+ io.puts(do_indent + ")\n")
76
+ else
77
+ io.puts(do_indent + @elements.to_sxp)
78
+ end
79
+ end
80
+
81
+ private
82
+ def do_indent(offset = 0); ' ' * (indent + offset); end
83
+ end
84
+
85
+ ##
86
+ # Format S-expressions to a String
87
+ #
6
88
  # @param [Array] sxps
7
89
  # @return [Object]
8
90
  def self.string(*sxps)
9
91
  require 'stringio' unless defined?(StringIO)
10
- write(StringIO.new, *sxps).instance_variable_get('@buffer').string
92
+ buf = StringIO.new
93
+ write(buf, *sxps)
94
+ buf.string
11
95
  end
12
96
 
13
97
  ##
98
+ # Format S-expressions to STDOUT
99
+ #
14
100
  # @param [Array] sxps
15
101
  # @return [Object]
16
102
  def self.print(*sxps)
@@ -18,73 +104,46 @@ module SXP
18
104
  end
19
105
 
20
106
  ##
107
+ # Write formatted S-expressions to an IO like object
108
+ #
21
109
  # @param [Object] out
22
110
  # @param [Array] sxps
23
111
  # @return [Object]
24
112
  def self.write(out, *sxps)
25
113
  generator = self.new(out)
26
114
  sxps.each do |sxp|
27
- generator.send((op = sxp.shift).to_sym, *sxp)
115
+ generator.render(sxp)
28
116
  end
29
117
  generator
30
118
  end
31
119
 
32
120
  ##
33
- # @param [Object] buffer
121
+ # Initialize output with a stack of IO buffers
122
+ #
123
+ # @param [#write] buffer
34
124
  def initialize(buffer)
35
- @output = [@buffer = buffer]
36
- @indent = 0
37
- end
38
-
39
- protected
40
-
41
- ##
42
- # @param [String] text
43
- # @param [Hash{Symbol => Object}] options
44
- # @return [void]
45
- def emit(text, options = {})
46
- if out = @output.last
47
- out.print(' ' * (indent * 2)) if options[:indent]
48
- out.print(text)
49
- end
50
- end
51
-
52
- ##
53
- # @yield
54
- # @return [String]
55
- def captured(&block)
56
- require 'stringio' unless defined?(StringIO)
57
- begin
58
- @output.push(buffer = StringIO.new)
59
- block.call
60
- ensure
61
- @output.pop
62
- end
63
- buffer.string
125
+ @output = buffer
64
126
  end
65
127
 
66
128
  ##
67
- # @yield
68
- # @return [Object]
69
- def indented(&block)
70
- begin
71
- increase_indent!
72
- block.call
73
- ensure
74
- decrease_indent!
129
+ # Render an element.
130
+ # For Array, this recursively renders each constituent into blocks.
131
+ # If the agregate length of a block is less than MIN_BLOCK characters,
132
+ # combine each constituent block into a single line.
133
+ #
134
+ # Rendering does not perform final formatting, but returns a recursive
135
+ # array of blocks which are each ultimattely formattted onto their
136
+ # own line with leading whitespace.
137
+ #
138
+ # @param [Object] sexp
139
+ # @return [Block]
140
+ def render(sexp)
141
+ block = Block.new(sexp, 0)
142
+ if block.length > 40
143
+ block.write(@output)
144
+ else
145
+ @output.puts(block.to_sxp)
75
146
  end
76
147
  end
77
-
78
- ##
79
- # @return [void]
80
- def increase_indent!
81
- @indent += 1
82
- end
83
-
84
- ##
85
- # @return [void]
86
- def decrease_indent!
87
- @indent -= 1
88
- end
89
148
  end # Generator
90
149
  end # SXP
data/lib/sxp/reader.rb CHANGED
@@ -22,16 +22,21 @@ module SXP
22
22
  # @return [Enumerable<Object>]
23
23
  def self.read_url(url, options = {})
24
24
  require 'open-uri'
25
- open(url.to_s, 'rb', nil, options) { |io| read_all(io, options) }
25
+ open(url.to_s, 'rb', nil, options) { |io| read_all(io, options).first }
26
26
  end
27
27
 
28
28
  ##
29
29
  # Reads all S-expressions from the given input files.
30
30
  #
31
- # @param [Enumerable<String>] filenames
32
- # @param [Hash{Symbol => Object}] options
31
+ # @overload read_files(*filenames)
32
+ # @param [Enumerable<String>] filenames
33
+ #
34
+ # @overload read_files(*filenames, options)
35
+ # @param [Enumerable<String>] filenames
36
+ # @param [Hash{Symbol => Object}] options
37
+ #
33
38
  # @return [Enumerable<Object>]
34
- def self.read_files(*filenames)
39
+ def read_files(*filenames)
35
40
  options = filenames.last.is_a?(Hash) ? filenames.pop : {}
36
41
  filenames.map { |filename| read_file(filename, options) }.inject { |sxps, sxp| sxps + sxp }
37
42
  end
@@ -43,7 +48,7 @@ module SXP
43
48
  # @param [Hash{Symbol => Object}] options
44
49
  # @return [Enumerable<Object>]
45
50
  def self.read_file(filename, options = {})
46
- File.open(filename.to_s, 'rb') { |io| read_all(io, options) }
51
+ File.open(filename.to_s, 'rb') { |io| read_all(io, options).first }
47
52
  end
48
53
 
49
54
  ##
@@ -55,13 +55,8 @@ module SXP; class Reader
55
55
  # @example Returning a URI prefix
56
56
  # parser.prefix(:dc) #=> RDF::URI('http://purl.org/dc/terms/')
57
57
  #
58
- # @overload prefix(name, uri)
59
- # @param [Symbol, #to_s] name
60
- # @param [RDF::URI, #to_s] uri
61
- #
62
- # @overload prefix(name)
63
- # @param [Symbol, #to_s] name
64
- #
58
+ # @param [Symbol, #to_s] name
59
+ # @param [RDF::URI, #to_s] uri
65
60
  # @return [RDF::URI]
66
61
  def prefix(name, uri = nil)
67
62
  name = name.to_s.empty? ? nil : (name.respond_to?(:to_sym) ? name.to_sym : name.to_s.to_sym)
data/lib/sxp/version.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  module SXP
2
2
  module VERSION
3
- MAJOR = 0
4
- MINOR = 0
5
- TINY = 14
6
- EXTRA = nil
3
+ VERSION_FILE = File.expand_path("../../../VERSION", __FILE__)
4
+ MAJOR, MINOR, TINY, EXTRA = File.read(VERSION_FILE).chop.split(".")
7
5
 
8
6
  STRING = [MAJOR, MINOR, TINY, EXTRA].compact.join('.')
9
7
 
metadata CHANGED
@@ -1,79 +1,74 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: sxp
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 14
9
- version: 0.0.14
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
10
6
  platform: ruby
11
- authors:
7
+ authors:
12
8
  - Arto Bendiken
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2011-04-04 00:00:00 +02:00
18
- default_executable: sxp2rdf
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
12
+ date: 2012-11-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
21
15
  name: json
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
24
17
  none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 1
30
- - 5
31
- - 1
32
- version: 1.5.1
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.4.6
33
22
  type: :runtime
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
36
- name: yard
37
23
  prerelease: false
38
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: !ruby/object:Gem::Requirement
39
25
  none: false
40
- requirements:
41
- - - ">="
42
- - !ruby/object:Gem::Version
43
- segments:
44
- - 0
45
- - 6
46
- - 4
47
- version: 0.6.4
48
- type: :development
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.6
30
+ - !ruby/object:Gem::Dependency
51
31
  name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: 2.12.0
38
+ type: :development
52
39
  prerelease: false
53
- requirement: &id003 !ruby/object:Gem::Requirement
40
+ version_requirements: !ruby/object:Gem::Requirement
54
41
  none: false
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- segments:
59
- - 2
60
- - 5
61
- - 0
62
- version: 2.5.0
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 2.12.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: yard
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: 0.8.3
63
54
  type: :development
64
- version_requirements: *id003
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.8.3
65
62
  description: A pure-Ruby implementation of a universal S-expression parser.
66
- email: arto.bendiken@gmail.com
67
- executables:
63
+ email: arto@bendiken.net
64
+ executables:
68
65
  - sxp2rdf
69
66
  - sxp2json
70
67
  - sxp2xml
71
68
  - sxp2yaml
72
69
  extensions: []
73
-
74
70
  extra_rdoc_files: []
75
-
76
- files:
71
+ files:
77
72
  - AUTHORS
78
73
  - CREDITS
79
74
  - README
@@ -96,39 +91,30 @@ files:
96
91
  - bin/sxp2json
97
92
  - bin/sxp2xml
98
93
  - bin/sxp2yaml
99
- has_rdoc: false
100
94
  homepage: http://sxp.rubyforge.org/
101
- licenses:
95
+ licenses:
102
96
  - Public Domain
103
97
  post_install_message:
104
98
  rdoc_options: []
105
-
106
- require_paths:
99
+ require_paths:
107
100
  - lib
108
- required_ruby_version: !ruby/object:Gem::Requirement
101
+ required_ruby_version: !ruby/object:Gem::Requirement
109
102
  none: false
110
- requirements:
111
- - - ">="
112
- - !ruby/object:Gem::Version
113
- segments:
114
- - 1
115
- - 8
116
- - 1
103
+ requirements:
104
+ - - ! '>='
105
+ - !ruby/object:Gem::Version
117
106
  version: 1.8.1
118
- required_rubygems_version: !ruby/object:Gem::Requirement
107
+ required_rubygems_version: !ruby/object:Gem::Requirement
119
108
  none: false
120
- requirements:
121
- - - ">="
122
- - !ruby/object:Gem::Version
123
- segments:
124
- - 0
125
- version: "0"
109
+ requirements:
110
+ - - ! '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
126
113
  requirements: []
127
-
128
114
  rubyforge_project: sxp
129
- rubygems_version: 1.3.7
115
+ rubygems_version: 1.8.24
130
116
  signing_key:
131
117
  specification_version: 3
132
118
  summary: A pure-Ruby implementation of a universal S-expression parser.
133
119
  test_files: []
134
-
120
+ has_rdoc: false