Continued implementation of extended attributes.
* Changed the `Issue` constructor to use an attribute map instead of an increasingly long parameter list. Of course we lose some control over required parameters. * Added the Joda Time and SLF4J logging libraries. * Implemented the `FileIssue` constructor for the new `Issue` refactor.
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								libpit/lib/joda-time-2.0.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libpit/lib/joda-time-2.0.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libpit/lib/logback-classic-0.9.26.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libpit/lib/logback-classic-0.9.26.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libpit/lib/logback-core-0.9.26.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libpit/lib/logback-core-0.9.26.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								libpit/lib/slf4j-api-1.6.1.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								libpit/lib/slf4j-api-1.6.1.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -1,10 +1,10 @@
 | 
			
		||||
#Wed, 26 Oct 2011 14:20:47 -0500
 | 
			
		||||
#Thu, 03 Nov 2011 13:47:05 -0500
 | 
			
		||||
#Sat Apr 24 17:08:00 CDT 2010
 | 
			
		||||
build.dir=build
 | 
			
		||||
src.dir=src
 | 
			
		||||
lib.shared.dir=../shared-libs
 | 
			
		||||
test.dir=test
 | 
			
		||||
build.number=0
 | 
			
		||||
build.number=11
 | 
			
		||||
expected.application.version=3.0.0
 | 
			
		||||
lib.dir=lib
 | 
			
		||||
release.dir=release
 | 
			
		||||
 
 | 
			
		||||
@@ -13,13 +13,20 @@ public abstract class Issue {
 | 
			
		||||
 | 
			
		||||
    protected Map extendedPropeties = [:]
 | 
			
		||||
 | 
			
		||||
    Issue(String id, Category c = Category.TASK, Status s = Status.NEW,
 | 
			
		||||
    int p = 9) {
 | 
			
		||||
        this.id = id
 | 
			
		||||
        this.category = c
 | 
			
		||||
        this.status = s
 | 
			
		||||
        this.priority = p
 | 
			
		||||
    }
 | 
			
		||||
    Issue(Map props) {
 | 
			
		||||
        this.id = props.id
 | 
			
		||||
        this.category = props.category ?: Category.TASK
 | 
			
		||||
        this.status = props.status ?: Status.NEW
 | 
			
		||||
        this.priority = props.priority ?: 9
 | 
			
		||||
        this.title = props.title ?: ''
 | 
			
		||||
        this.text = props.text ?: ''
 | 
			
		||||
 | 
			
		||||
        def nativeProps =
 | 
			
		||||
            ["id", "category", "status", "priority", "title", "text"]
 | 
			
		||||
 | 
			
		||||
        props.each { key, val ->
 | 
			
		||||
            if (nativeProps.contains(key)) { return }
 | 
			
		||||
            this.extendedProperties[key] = val }}
 | 
			
		||||
 | 
			
		||||
    public String getId() { return id; }
 | 
			
		||||
 | 
			
		||||
@@ -49,7 +56,7 @@ public abstract class Issue {
 | 
			
		||||
 | 
			
		||||
    public String getTitle() { return title }
 | 
			
		||||
 | 
			
		||||
    public String setTitle(String t) throws IOException { title = t }
 | 
			
		||||
    public void setTitle(String t) throws IOException { title = t }
 | 
			
		||||
 | 
			
		||||
    public String getText() { return text }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,31 +1,75 @@
 | 
			
		||||
package com.jdbernard.pit.file
 | 
			
		||||
 | 
			
		||||
import com.jdbernard.pit.*
 | 
			
		||||
 | 
			
		||||
import java.lang.IllegalArgumentException as IAE
 | 
			
		||||
 | 
			
		||||
import org.joda.time.DateMidnight
 | 
			
		||||
import org.joda.time.DateTime
 | 
			
		||||
 | 
			
		||||
import org.slf4j.Logger
 | 
			
		||||
import org.slf4j.LoggerFactory
 | 
			
		||||
 | 
			
		||||
public class FileIssue extends Issue {
 | 
			
		||||
 | 
			
		||||
    protected File source
 | 
			
		||||
    private Logger log = LoggerFactory.getLogger(getClass())
 | 
			
		||||
 | 
			
		||||
    public static final String fileExp = /(\d+)([bft])([ajnsv])(\d).*/
 | 
			
		||||
 | 
			
		||||
    public FileIssue(File file) {
 | 
			
		||||
 | 
			
		||||
        super('REPLACE_ME')
 | 
			
		||||
        super(id: -1, title: 'REPLACE_ME')
 | 
			
		||||
 | 
			
		||||
        if (log.isDebugEnabled()) {
 | 
			
		||||
            log.debug("Loading a FileIssue from '{}'", file.canonicalPath) }
 | 
			
		||||
 | 
			
		||||
        def matcher = file.name =~ fileExp
 | 
			
		||||
        if (!matcher)
 | 
			
		||||
            throw new IllegalArgumentException("${file} " +
 | 
			
		||||
                "is not a valid Issue file.")
 | 
			
		||||
 | 
			
		||||
        // Read issue attributes from the filename.
 | 
			
		||||
        super.@id = matcher[0][1]
 | 
			
		||||
        super.@category = Category.toCategory(matcher[0][2])
 | 
			
		||||
        super.@status = Status.toStatus(matcher[0][3])
 | 
			
		||||
        super.@priority = matcher[0][4].toInteger()
 | 
			
		||||
 | 
			
		||||
        log.debug("id: {}\tcategory: {}\tstatus: {}\tpriority: {}",
 | 
			
		||||
            [super.@id, super.@category, super.@status, super.@priority])
 | 
			
		||||
 | 
			
		||||
        this.source = file
 | 
			
		||||
 | 
			
		||||
        super.@text = file.text
 | 
			
		||||
        super.@title = super.@text.readLines()[0]
 | 
			
		||||
        String text = ""
 | 
			
		||||
        boolean parsingText = true
 | 
			
		||||
 | 
			
		||||
        // Now parse the actual file contents.
 | 
			
		||||
        file.text.eachLine { line, lineNumber ->
 | 
			
		||||
 | 
			
		||||
            log.trace("lineNumber: {}, line: {}", lineNumber, line)
 | 
			
		||||
 | 
			
		||||
            if (lineNumber == 0) {
 | 
			
		||||
                super.@title = line
 | 
			
		||||
                log.debug("Found title: {}", super.@title) }
 | 
			
		||||
 | 
			
		||||
            else if (lineNumber > 2) {
 | 
			
		||||
                // We see the horizontal rule
 | 
			
		||||
                if (line ==~ /\s*^\-{4}\-*\s*$/) { parsingText = false }
 | 
			
		||||
 | 
			
		||||
                if (parsingText) { text += "$line\n" }
 | 
			
		||||
 | 
			
		||||
                else {
 | 
			
		||||
                    def match = (line =~ /^([^:]+):(.+)$/)
 | 
			
		||||
                    if (match) {
 | 
			
		||||
                        def key = match[0][1].trim()
 | 
			
		||||
                        def value = parseValue(match[0][2].trim())
 | 
			
		||||
                        super.@extendedProperties[key] = value
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        super.@text = text
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setCategory(Category c) throws IOException {
 | 
			
		||||
@@ -109,22 +153,22 @@ public class FileIssue extends Issue {
 | 
			
		||||
 | 
			
		||||
    public static String formatIssue(Issue issue) {
 | 
			
		||||
        def result = new StringBuilder()
 | 
			
		||||
        result.append(title)
 | 
			
		||||
        result.append(issue.@title)
 | 
			
		||||
        result.append("\n")
 | 
			
		||||
        result.append("=".multiply(title.length()))
 | 
			
		||||
        result.append("=".multiply(issue.@title.length()))
 | 
			
		||||
        result.append("\n")
 | 
			
		||||
        result.append(text)
 | 
			
		||||
        result.append(issue.@text)
 | 
			
		||||
        result.append("\n----\n")
 | 
			
		||||
 | 
			
		||||
        // If there are any extended properties, let's write those.
 | 
			
		||||
        if (super.@extendedProperties.size() > 0) {
 | 
			
		||||
        if (issue.@extendedProperties.size() > 0) {
 | 
			
		||||
            def extOutput = [:]
 | 
			
		||||
            def maxKeyLen = 0
 | 
			
		||||
            def maxValLen = 0
 | 
			
		||||
 | 
			
		||||
            // Find the longest key and value, convert all to strings.
 | 
			
		||||
            super.@extendedProperties.each { key, val ->
 | 
			
		||||
                def ks = key.toString(), vs = val.toString()
 | 
			
		||||
            issue.@extendedProperties.each { key, val ->
 | 
			
		||||
                def ks = key.toString(), vs = formatProperty(val)
 | 
			
		||||
                extOutput[ks] = vs
 | 
			
		||||
                if (ks.length() > maxKeyLen) { maxKeyLen = ks.length() }
 | 
			
		||||
                if (vs.length() > maxKeyLen) { maxValLen = vs.length() } }
 | 
			
		||||
@@ -146,7 +190,7 @@ public class FileIssue extends Issue {
 | 
			
		||||
            result.append("\n") }}
 | 
			
		||||
 | 
			
		||||
    protected void writeFile() {
 | 
			
		||||
        try { source.write(formatIssue(this) }
 | 
			
		||||
        try { source.write(formatIssue(this)) }
 | 
			
		||||
        catch (IOException ioe) {
 | 
			
		||||
            throw new IOException("I could not save the new text for this "
 | 
			
		||||
                + "issue. I can not write to the file for this issue. I do not"
 | 
			
		||||
@@ -154,4 +198,16 @@ public class FileIssue extends Issue {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public def parseValue(String value) {
 | 
			
		||||
        switch (value) {
 | 
			
		||||
            case ~/\d{4}-\d{2}-\d{2}/: return DateMidnight.parse(value)
 | 
			
		||||
            default: return value
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String formatProperty(DateTime prop) {
 | 
			
		||||
        return prop.format("YYYY-MM-dd'T'HH:mm:ss") }
 | 
			
		||||
 | 
			
		||||
    public String formatProperty(DateMidnight prop) {
 | 
			
		||||
        return prop.format("YYYY-MM-dd") }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@ package com.jdbernard.pit
 | 
			
		||||
 | 
			
		||||
public class MockIssue extends Issue {
 | 
			
		||||
    public MockIssue(String id, Category c, Status s, int p) {
 | 
			
		||||
        super (id, c, s, p)
 | 
			
		||||
        super ([id: id, category: c, status: s, priority: p])
 | 
			
		||||
    }
 | 
			
		||||
    public boolean delete() { return true }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -171,9 +171,7 @@ class FileIssueTest {
 | 
			
		||||
        assertEquals issue.status    , Status.NEW
 | 
			
		||||
        assertEquals issue.priority  , 1
 | 
			
		||||
        assertEquals issue.title     , "Add the killer feature to the killer app."
 | 
			
		||||
        assertEquals issue.text      , "Add the killer feature to the killer app.\n" +
 | 
			
		||||
                                      "=========================================\n\n" +
 | 
			
		||||
                                      "Make our killer app shine!."
 | 
			
		||||
        assertEquals issue.text      , "Make our killer app shine!."
 | 
			
		||||
        assertEquals issue.source    , issueFile
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user