Skip to content
Browse files

initial spec tests, doing TDD this time ;)

  • Loading branch information...
1 parent eb39934 commit 1d4bddb909260a34b068300a77612cdefe06244e @brianmario committed Jul 29, 2009
Showing with 231 additions and 18 deletions.
  1. +15 −0 Rakefile
  2. +8 −0 lib/json_machine.rb
  3. +11 −0 lib/json_machine/encoder.rb
  4. +108 −0 lib/json_machine/parser.rb
  5. +41 −18 parser.rb
  6. +38 −0 spec/parsing_spec.rb
  7. +4 −0 spec/rcov.opts
  8. +2 −0 spec/spec.opts
  9. +4 −0 spec/spec_helper.rb
View
15 Rakefile
@@ -0,0 +1,15 @@
+require 'rake'
+require 'spec/rake/spectask'
+
+desc "Run all examples with RCov"
+Spec::Rake::SpecTask.new('spec:rcov') do |t|
+ t.spec_files = FileList['spec/']
+ t.rcov = true
+ t.rcov_opts = lambda do
+ IO.readlines("spec/rcov.opts").map {|l| l.chomp.split " "}.flatten
+ end
+end
+Spec::Rake::SpecTask.new('spec') do |t|
+ t.spec_files = FileList['spec/']
+ t.spec_opts << '--options' << 'spec/spec.opts'
+end
View
8 lib/json_machine.rb
@@ -0,0 +1,8 @@
+# encoding: UTF-8
+
+require 'json_machine/parser'
+require 'json_machine/encoder'
+
+module JsonMachine
+ VERSION = "0.1.0"
+end
View
11 lib/json_machine/encoder.rb
@@ -0,0 +1,11 @@
+# encoding: UTF-8
+
+module JsonMachine
+ class Encoder
+ def initialize(opts={})
+ end
+
+ def encode(obj, str_or_io=nil)
+ end
+ end
+end
View
108 lib/json_machine/parser.rb
@@ -0,0 +1,108 @@
+# encoding: UTF-8
+
+module JsonMachine
+ class Parser
+ NULL = "null".freeze
+ TRUE = "true".freeze
+ FALSE = "false".freeze
+
+ def initialize(opts={})
+ # TODO: setup options
+ end
+
+ def parse(str_or_io)
+ str_or_io = StringIO.new(str_or_io) if str_or_io.is_a?(String)
+ current_value = ""
+ while char = str_or_io.read(1)
+ case char
+ when '"'
+ if parse_string(str_or_io, current_value)
+ return current_value
+ else
+ # TODO: throw exception?
+ end
+ when /[0-9]/ # probably a number
+ current_value = char
+ if parse_number(str_or_io, current_value)
+ return current_value
+ else
+ # TODO: raise exception?
+ end
+ when 'n' # probably null
+ current_value = char
+ if parse_null(str_or_io, current_value)
+ return nil
+ else
+ # TODO: raise exception?
+ end
+ when 't' # probably true
+ current_value = char
+ if parse_true(str_or_io, current_value)
+ return true
+ else
+ # TODO: raise exception?
+ end
+ when 'f' # probably false
+ current_value = char
+ if parse_false(str_or_io, current_value)
+ return false
+ else
+ # TODO: raise exception?
+ end
+ when '{' # probably the start of a hash
+ when '[' # probably the start of an array
+ else
+ if char == "'"
+ # TODO: throw exception?
+ # This is the case where we're parsing a string that should be wrapped with double-quotes
+ # Either a hash key or string value
+ end
+ # TODO: something here?
+ end
+ end
+ end
+
+ protected
+ def parse_string(io, out_str)
+ while char = io.read(1)
+ return true if char == '"'
+ out_str << char
+ end
+ return false
+ end
+
+ def parse_number(io, out_str)
+ while char = io.read(1)
+ return if char == ','
+ out_str << char
+ end
+ end
+
+ def parse_true(io, out_str)
+ out_str << io.read(3)
+ if out_str != TRUE
+ return false
+ else
+ return true
+ end
+ end
+
+ def parse_false(io, out_str)
+ out_str << io.read(4)
+ if out_str != FALSE
+ return false
+ else
+ return true
+ end
+ end
+
+ def parse_null(io, out_str)
+ out_str << io.read(3)
+ if out_str != NULL
+ return false
+ else
+ return true
+ end
+ end
+ end
+end
View
59 parser.rb
@@ -1,3 +1,5 @@
+# encoding: UTF-8
+
require 'rubygems'
require 'benchmark'
require 'yajl'
@@ -55,13 +57,10 @@ def parse(str_or_io)
while char = str_or_io.read(1)
case @state
when :wants_hash_key
- if char == '"' # end of the hash key
- found_hash_key(current_value)
- current_value.replace('')
- @state = :wants_hash_value
- else
- current_value << char
- end
+ parse_string(str_or_io, current_value)
+ found_hash_key(current_value)
+ current_value.replace('')
+ @state = :wants_hash_value
when :wants_hash_value
case char
when ':'
@@ -76,7 +75,7 @@ def parse(str_or_io)
parse_string(str_or_io, current_value)
found_string(current_value)
current_value.replace('')
- @state = :wants_anything
+ @state = :wants_another_hash_key
when '{' # value is another hash
found_start_hash
str_or_io.read(1) # read off the '"' char
@@ -86,21 +85,21 @@ def parse(str_or_io)
val = char
val << str_or_io.read(3)
found_nil if val == 'null'
- @state = :wants_anything
+ @state = :wants_another_hash_key
when 't' # value is probably 'true'
val = char
val << str_or_io.read(3)
found_boolean(true) if val == 'true'
- @state = :wants_anything
+ @state = :wants_another_hash_key
when 'f' # value is probably 'false'
val = char
val << str_or_io.read(3)
found_boolean(false) if val == 'false'
- @state = :wants_anything
+ @state = :wants_another_hash_key
when /[0-9]/, '-' # value is probably a number
current_value << char
end
- when :wants_anything
+ when :wants_anything, :wants_array_value, :wants_another_hash_key
case char
when '{'
found_start_hash
@@ -113,21 +112,45 @@ def parse(str_or_io)
found_end_hash
when ']'
found_end_array
+ when ','
+ if @state == :wants_array_value
+ puts "array value"
+ # char = str_or_io.read(1)
+ elsif @state == :wants_another_hash_key
+ @state = :wants_hash_key
+ end
end
end
end
end
- def parse_string(str_or_io, out_str)
- while char = str_or_io.read(1)
- return if char == '"'
- out_str << char
+ protected
+ def parse_number(io, out_str)
+ while char = str_or_io.read(1)
+ return if char == ','
+ out_str << char
+ end
+ end
+
+ def parse_bool(io, out_str)
+ out_str << io.read(3)
+ end
+
+ def parse_null(io, out_str)
+ out_str << io.read(3)
+ end
+
+ # Assumes it's being handed the IO at the position
+ def parse_string(io, out_str)
+ while char = str_or_io.read(1)
+ return if char == '"'
+ out_str << char
+ end
end
- end
end
json = '{"item": {"name": "generated", "cached_tag_list": "", "updated_at": "2009-03-24T05:25:09Z", "updated_by_id": null, "price": 1.99, "delta": false, "cost": 0.597, "account_id": 16, "unit": null, "import_tag": null, "taxable": true, "id": 1, "created_by_id": null, "description": null, "company_id": 0, "sku": "06317-0306", "created_at": "2009-03-24T05:25:09Z", "active": true}}'
-
+# puts json
Benchmark.bm do |x|
x.report do
JsonMachine.parse(json)
View
38 spec/parsing_spec.rb
@@ -0,0 +1,38 @@
+# encoding: UTF-8
+require File.join(File.dirname(__FILE__), 'spec_helper.rb')
+
+describe "JsonMachine::Parser" do
+ before(:each) do
+ @parser = JsonMachine::Parser.new
+ end
+
+ it "should parse a string" do
+ @parser.parse('"this is a string"').should == "this is a string"
+ end
+
+ it "should parse a number" do
+ @parser.parse('123456').should == 123456
+ end
+
+ it "should parse a simple hash" do
+ pending
+ @parser.parse('{"key":"value"}').should == {"key" => "value"}
+ end
+
+ it "should parse a simple array" do
+ pending
+ @parser.parse('["value", "value2"]').should == ["value", "value2"]
+ end
+
+ it "should parse a boolean (true)" do
+ @parser.parse('true').should == true
+ end
+
+ it "should parse a boolean (false)" do
+ @parser.parse('false').should == false
+ end
+
+ it "should parse null" do
+ @parser.parse('null').should == nil
+ end
+end
View
4 spec/rcov.opts
@@ -0,0 +1,4 @@
+--exclude spec,gem
+--text-summary
+--spec-only
+--sort coverage --sort-reverse
View
2 spec/spec.opts
@@ -0,0 +1,2 @@
+--format specdoc
+--colour
View
4 spec/spec_helper.rb
@@ -0,0 +1,4 @@
+# encoding: UTF-8
+$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
+
+require 'json_machine'

0 comments on commit 1d4bddb

Please sign in to comment.
Something went wrong with that request. Please try again.