Skip to content
Browse files

draft

  • Loading branch information...
0 parents commit 05a2e32dbe1b3951a21c70180e5f7813ec1000aa @kachick committed Jul 12, 2012
Showing with 155 additions and 0 deletions.
  1. +26 −0 .gitignore
  2. +58 −0 example.rb
  3. +71 −0 lib/sugarparser.rb
26 .gitignore
@@ -0,0 +1,26 @@
+*.gem
+*.rbc
+.bundle
+.config
+coverage
+coverage.data
+InstalledFiles
+lib/bundler/man
+pkg
+rdoc
+spec/reports
+test/tmp
+test/version_tmp
+tmp
+
+# YARD artifacts
+.yardoc
+_yardoc
+doc/
+
+# tmp-old
+.old
+
+# editor
+*~
+.redcar
58 example.rb
@@ -0,0 +1,58 @@
+#!/usr/local/bin/ruby -w
+
+$VERSION = true
+
+require_relative 'lib/sugarparser'
+
+class MyConfig
+
+ Entry = Struct.new :name, :param, :comment
+
+ Parser = SugarParser.define self do |instance|
+ separator = /^-+\n/
+
+ trim(/\AHello, my too specific foolish config!\n/)
+
+ must(/^Foolish Syntax Version (\d+\.\d+)\n/){|s, version|
+ instance.version = version.to_f
+ }
+
+ trim separator
+ trim(/^Index. Name Param Comment\n/)
+ trim separator
+
+ while (
+ try(/^(\d+)\.\s+(\S+)\s+(\S+)\s+(\S+)\n/) do |s, idx, name, param, comment|
+ instance.entries[idx.to_i] = Entry.new(name, param, comment)
+ end
+ ); end
+
+ trim separator
+ trim(/^Bye!!/)
+ end
+
+ def self.parse(str)
+ Parser.parse str
+ end
+
+ attr_accessor :version, :entries
+
+ def initialize
+ @version = nil
+ @entries = []
+ end
+
+end
+
+p MyConfig.parse(DATA.read)
+
+__END__
+Hello, my too specific foolish config!
+Foolish Syntax Version 2.1
+-------------------------------------------------------------------------------
+Index. Name Param Comment
+-------------------------------------------------------------------------------
+1. AAA abc1234 afda
+2. BBB ggggg umm
+-------------------------------------------------------------------------------
+Bye!!
71 lib/sugarparser.rb
@@ -0,0 +1,71 @@
+# Copyright (c) 2012 Kenichi Kamiya
+
+require 'strscan'
+require 'forwardable'
+
+class SugarParser
+
+ class ParsingError < RuntimeError; end
+
+ class << self
+
+ def define(klass, &scenario)
+ Class.new(self).tap do |concrete|
+ concrete.class_eval do
+
+ extend Forwardable
+
+ singleton_class.class_eval do
+
+ def parse(str)
+ new(str).run
+ end
+
+ end
+
+ define_method :initialize do |str|
+ @result = klass.new
+ @scanner = StringScanner.new str
+ end
+
+ def_delegators :@scanner, :eos?, :rest, :rest?, :peek,
+ :scan, :check, :skip
+
+ define_method :run do
+ instance_exec @result, &scenario
+ raise ParsingError unless eos?
+ @result
+ end
+
+ def trim(rxp)
+ unless skip rxp
+ raise ParsingError, rest.lines.first
+ end
+ end
+
+ def must(rxp, &block)
+ unless try(rxp, &block)
+ raise ParsingError, rest.lines.first
+ end
+ end
+
+ def try(rxp, &block)
+ if scan(rxp)
+ block.call(* captures(block.arity))
+ end
+ end
+
+ private
+
+ def captures(length)
+ (0..length).map{|n|@scanner[n]}
+ end
+
+ end
+
+ end
+ end
+
+ end
+
+end

0 comments on commit 05a2e32

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