Skip to content

Instantly share code, notes, and snippets.

@josefbetancourt
Last active December 9, 2015 22:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save josefbetancourt/4336584 to your computer and use it in GitHub Desktop.
Save josefbetancourt/4336584 to your computer and use it in GitHub Desktop.
Groovy source code from blog post "A very simple data file metaformat" at http://octodecillion.com/blog/very-simple-data-file-format/
package com.octodecillion.inix
import java.util.regex.Pattern
import groovy.transform.TypeChecked
import java.util.regex.Matcher
/**
*
*
* @author Josef Betancourt
*
*/
class Inix {
String iniFilePath
Reader reader
int lineNum
int sectionNum
Event data
def state = State.INIT
/**
* Value object for parsed sections.
*
*/
class Event {
EventType event
String subsection
String id
String text
int lineNum
int sectionNum
String sectionString
String toString() {
return "id=[$id],subsection=[$subsection]"
};
}
Event getEvent(){
return data
}
/**
* Pull event style processing.
*
* @return event structure
*/
EventType next(){
String line = reader.readLine()
lineNum++
if(line == null){
return EventType.END
}
if( isBlank(line)){
skipLines(reader)
}
if(line == null){
return EventType.END
}
String type =''
String subsection = ''
String id = ''
data = new Event()
EventType eventType
line = line.trim()
if(isComment(line)){
data.text = line
data.event = EventType.COMMENT
data.lineNum = lineNum
eventType = EventType.COMMENT
}
if(isSection(line)){ // section?
eventType = EventType.SECTION
data.sectionString = line
sectionNum++
processSection(line, sectionNum, data)
} // end if section head
return eventType
}
/**
* Get metadata and content of section.
*
* @param line
* @return
*/
def processSection(String line, int sectionNum, Event data){
data.event = EventType.SECTION
data.sectionNum = sectionNum
Matcher m = (line =~ /^\[>(.*)\]/)
String mString = m[0][1]
def current = mString.trim()
if(!current){
def msg = "section $sectionNum is blank"
throw new IllegalArgumentException(msg)
}
def parts = (current =~ /^(.*)\/(.*)$/)
if(!parts){
data.id = current
}else{
long size = ((String[])parts[0]).length
data.id = size > 1 ? parts[0][1] : ''
data.subsection = size > 2 ? parts[0][2] : ''
}
String readData = readSectionData()
data.text = readData
}
/**
* Get data in section.
*
* @return data as string
*/
String readSectionData(){
StringBuilder buffer = new StringBuilder(8*1024)
while(true){
String line = reader.readLine()
lineNum++
if(line == null){
break
}
line = line.trim()
if(isEnd(line)){
break
}else if(isSection(line)){
throw new IllegalArgumentException("Unterminated section")
}else{
buffer.append(line + LINESEP)
}
}
return buffer.toString()
}
def skipLines(reader){
while(true){
line = reader.readLine()
lineNum++
if(line || line == null){
break
}
}
}
def isSection(line){
return line =~ /^\[>.*\]/
}
def isEnd(line){
return line =~ /^\[<.*\]/ || line =~ /^\[>.*\]/
}
def isBlank(s) {
return (s == null ? false : (s.trim().length() ==0 ? true : false))
}
def isComment(line) {
return line =~ /^\s*[#;]/
}
private static final String BLANK = ""
static final String LINESEP = System.getProperty("line.separator")
enum State {
INIT, ACCEPT, SHIFT, END
}
public enum EventType {
COMMENT, SECTION, END
}
} // end of class Inix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment