develapp-tardef 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +18 -0
- data/Rakefile +1 -0
- data/bin/tardef +105 -0
- data/lib/tardef.rb +14 -0
- data/lib/tardef/base.rb +126 -0
- data/lib/tardef/connector/base.rb +66 -0
- data/lib/tardef/connector/json.rb +16 -0
- data/lib/tardef/connector/xml.rb +18 -0
- data/lib/tardef/connector/yaml.rb +16 -0
- data/lib/tardef/object.rb +29 -0
- data/lib/tardef/validator/base.rb +34 -0
- data/lib/tardef/validator/extensions.rb +39 -0
- data/lib/tardef/validator/links.rb +34 -0
- data/lib/tardef/validator/syntax.rb +27 -0
- data/lib/tardef/version.rb +3 -0
- data/schema/v1/extension/attachement.yaml +15 -0
- data/schema/v1/extension/location.yaml +12 -0
- data/schema/v1/extension/reminder.yaml +20 -0
- data/schema/v1/tardef.yaml +106 -0
- data/tardef.gemspec +28 -0
- metadata +152 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c25ba53a04efb4aa4396b3510a48600faf67bc5b
|
4
|
+
data.tar.gz: 2db69cf4bfee5c09da16091a9caef1e552baaf36
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 32acbdfdb908e15596f9b17e2371e09436d4c249c204148204957ba2ea2a18b327ed5b7c29a4741ad9e19523f3b2387c69558d13cb71068a3752d415f8335b15
|
7
|
+
data.tar.gz: 96070238616ede59b1ed1a44dd6aeefd151c1704829b9471715890ebbc1dff217acbddb5c0bce7df61c55d89bc8aa3d7db7438570a33a53c87a1daffe21957b9
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Timo Puschkasch
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
TARDEF - Task And Related Data Exchange Format
|
2
|
+
====
|
3
|
+
TARDEF is a format for saving and exchanging data for tasks and related data - like lists and tags - in an easy format. By default, YAML and JSON are supported as file formats by TARDEF, but any format that supports the same kind of structures as YAML / JSON could be used.
|
4
|
+
|
5
|
+
Advantages
|
6
|
+
===
|
7
|
+
* Text based: Files can be read and written by humans and also supports versioning files using Git, SVN, etc.
|
8
|
+
* Extensions: Extensions can be used to add functionality to the TARDEF file that is not supported by the default format.
|
9
|
+
|
10
|
+
Usage
|
11
|
+
===
|
12
|
+
The TARDEF repository contains a Ruby library that can be used for accessing the files. There are also schemas following the Kwalify (http://www.kuwata-lab.com/kwalify/) standard that can be used for validating TARDEF files. A ruby tool for doing so is also included.
|
13
|
+
|
14
|
+
The validator can be used by calling tardef_validate -f <file> -t <type>
|
15
|
+
|
16
|
+
File Format Description
|
17
|
+
===
|
18
|
+
Coming soon...
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/tardef
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "tardef"
|
3
|
+
|
4
|
+
# Set some basic variables
|
5
|
+
input_file = ""
|
6
|
+
input_type = ""
|
7
|
+
output_file = ""
|
8
|
+
output_type = ""
|
9
|
+
command = ""
|
10
|
+
|
11
|
+
def check_type(type)
|
12
|
+
if type == ""
|
13
|
+
puts "[ERROR] Type could not be derived from file name and must not be empty"
|
14
|
+
exit
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_connector(type, file)
|
19
|
+
connector = nil
|
20
|
+
if type == "yaml"
|
21
|
+
connector = Tardef::Connector::YAML.new(file)
|
22
|
+
elsif type == "json"
|
23
|
+
connector = Tardef::Connector::JSON.new(file)
|
24
|
+
elsif type == "xml"
|
25
|
+
connector = Tardef::Connector::XML.new(file)
|
26
|
+
end
|
27
|
+
connector
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_file(file, type)
|
31
|
+
reader = get_connector(type, file)
|
32
|
+
reader.read
|
33
|
+
end
|
34
|
+
|
35
|
+
def write_file(file, type, obj)
|
36
|
+
writer = get_connector(type, file)
|
37
|
+
writer.write(obj)
|
38
|
+
end
|
39
|
+
|
40
|
+
def derive_type(file, type)
|
41
|
+
if type == ""
|
42
|
+
if file.end_with?(".yaml")
|
43
|
+
type = "yaml"
|
44
|
+
elsif file.end_with?(".json")
|
45
|
+
type = "json"
|
46
|
+
elsif file.end_with?(".xml")
|
47
|
+
type = "xml"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
type
|
51
|
+
end
|
52
|
+
|
53
|
+
command = ARGV[0]
|
54
|
+
ARGV.each_with_index do |arg, index|
|
55
|
+
if arg == "-if"
|
56
|
+
input_file = ARGV[index + 1]
|
57
|
+
elsif arg == "-of"
|
58
|
+
output_file = ARGV[index + 1]
|
59
|
+
elsif arg == "-it"
|
60
|
+
input_type = ARGV[index + 1]
|
61
|
+
elsif arg == "-ot"
|
62
|
+
output_type = ARGV[index + 1]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
if input_file == ""
|
67
|
+
puts "[ERROR] Input file must be given using -if <filename>"
|
68
|
+
exit
|
69
|
+
end
|
70
|
+
|
71
|
+
input_type = derive_type(input_file, input_type)
|
72
|
+
output_type = derive_type(output_file, output_type)
|
73
|
+
check_type(input_type)
|
74
|
+
|
75
|
+
begin
|
76
|
+
if command == "validate"
|
77
|
+
obj = read_file(input_file, input_type)
|
78
|
+
chain = Tardef::Validator::Chain.new
|
79
|
+
chain.add_validator(Tardef::Validator::Links.new)
|
80
|
+
chain.add_validator(Tardef::Validator::Extensions.new)
|
81
|
+
chain.add_validator(Tardef::Validator::Syntax.new(obj.schema))
|
82
|
+
result = chain.validate(obj)
|
83
|
+
|
84
|
+
if result.empty?
|
85
|
+
puts "[SUCCESS] File is valid"
|
86
|
+
else
|
87
|
+
puts "[ERROR] Validation errors found:\n"
|
88
|
+
puts result
|
89
|
+
end
|
90
|
+
elsif command == "transform"
|
91
|
+
if output_file == ""
|
92
|
+
puts "[ERROR] Output file must be given using -of <filename>"
|
93
|
+
exit
|
94
|
+
end
|
95
|
+
check_type(output_type)
|
96
|
+
obj = read_file(input_file, input_type)
|
97
|
+
write_file(output_file, output_type, obj)
|
98
|
+
puts "[SUCCESS] File transformed"
|
99
|
+
else
|
100
|
+
raise "Command #{command} missing"
|
101
|
+
end
|
102
|
+
rescue Exception => e
|
103
|
+
puts "[ERROR] #{e.to_s}"
|
104
|
+
end
|
105
|
+
|
data/lib/tardef.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Make sure we don't catch any loading issues
|
2
|
+
$LOAD_PATH << '.'
|
3
|
+
|
4
|
+
require "tardef/base"
|
5
|
+
require "tardef/version"
|
6
|
+
require "tardef/object"
|
7
|
+
require "tardef/connector/base"
|
8
|
+
require "tardef/connector/yaml"
|
9
|
+
require "tardef/connector/json"
|
10
|
+
require "tardef/connector/xml"
|
11
|
+
require "tardef/validator/base"
|
12
|
+
require "tardef/validator/links"
|
13
|
+
require "tardef/validator/syntax"
|
14
|
+
require "tardef/validator/extensions"
|
data/lib/tardef/base.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
##
|
2
|
+
# Base class for objects
|
3
|
+
module Tardef
|
4
|
+
class Base
|
5
|
+
attr_accessor :extensions
|
6
|
+
|
7
|
+
def add_extension(extension)
|
8
|
+
@extensions << extension
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.parse_date(datestring)
|
12
|
+
return DateTime.iso8601(datestring)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_hash
|
16
|
+
hash = {}
|
17
|
+
# Add all instance variables
|
18
|
+
instance_variables.each do |var|
|
19
|
+
if not instance_variable_get(var) or instance_variable_get(var).empty?
|
20
|
+
next
|
21
|
+
end
|
22
|
+
hash[var.to_s.delete("@")] = instance_variable_get(var)
|
23
|
+
end
|
24
|
+
# Tidy up the extensions by making them hashes
|
25
|
+
return hash if not hash["extensions"]
|
26
|
+
extensions = []
|
27
|
+
hash["extensions"].each do |extension|
|
28
|
+
extensions << extension.to_hash
|
29
|
+
end
|
30
|
+
hash["extensions"] = extensions
|
31
|
+
hash
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_hash(hash)
|
35
|
+
hash.each do |key, value|
|
36
|
+
key = "@" + key
|
37
|
+
if instance_variable_defined?(key)
|
38
|
+
instance_variable_set(key, value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return unless @extensions
|
42
|
+
|
43
|
+
extension_list = []
|
44
|
+
@extensions.each do |extension|
|
45
|
+
ext = Extension.new(nil, nil)
|
46
|
+
ext.load_hash(extension)
|
47
|
+
extension_list << ext
|
48
|
+
end
|
49
|
+
@extensions = extension_list
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
@extensions = []
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class Extension < Base
|
58
|
+
attr_accessor :name, :data
|
59
|
+
|
60
|
+
def initialize(name, schema)
|
61
|
+
@name, @data = name, data
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class File < Base
|
66
|
+
attr_accessor :filename, :title, :editor, :imports, :schema
|
67
|
+
attr_accessor :last_changed, :lists, :tags, :tasks, :extension_defs
|
68
|
+
|
69
|
+
def initialize(filename, protocol_version, last_changed, title = "", editor = "", imports = [], schema = "")
|
70
|
+
super()
|
71
|
+
@filename, @last_changed, @title = filename, last_changed, title
|
72
|
+
@editor, @lists, @tags, @tasks, @imports = editor, [], [], [], imports
|
73
|
+
@schema = schema
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_list(list)
|
77
|
+
@lists << list
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_tag(tag)
|
81
|
+
@tags << tag
|
82
|
+
end
|
83
|
+
|
84
|
+
def add_task(task)
|
85
|
+
@tasks << task
|
86
|
+
end
|
87
|
+
|
88
|
+
def hash_has_object?(list, uid)
|
89
|
+
list.each { |item| return true if item.uid == uid }
|
90
|
+
return false
|
91
|
+
end
|
92
|
+
|
93
|
+
def has_list?(uid)
|
94
|
+
hash_has_object?(@lists, uid)
|
95
|
+
end
|
96
|
+
|
97
|
+
def has_tag?(tag)
|
98
|
+
hash_has_object?(@tags, tag)
|
99
|
+
end
|
100
|
+
|
101
|
+
def has_task?(task)
|
102
|
+
hash_has_object?(@tasks, task)
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_hash
|
106
|
+
hash = {"meta" => {
|
107
|
+
"title" => @title, "editor" => @editor, "last_changed" => @last_changed,
|
108
|
+
"imports" => @imports
|
109
|
+
},
|
110
|
+
"lists" => @lists, "tags" => @tags, "tasks" => @tasks, "schema" => @schema,
|
111
|
+
"extensions" => @extensions,
|
112
|
+
}
|
113
|
+
|
114
|
+
items = []
|
115
|
+
["lists", "tags", "tasks", "extensions"].each do |type|
|
116
|
+
next if not hash[type]
|
117
|
+
items = []
|
118
|
+
hash[type].each do |item|
|
119
|
+
items << item.to_hash
|
120
|
+
end
|
121
|
+
hash[type] = items
|
122
|
+
end
|
123
|
+
return hash
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Tardef::Connector
|
2
|
+
class Base
|
3
|
+
@filename = ""
|
4
|
+
@can_read = true
|
5
|
+
@can_write = true
|
6
|
+
|
7
|
+
attr_accessor :filename
|
8
|
+
|
9
|
+
def read
|
10
|
+
raise "Connector is write-only" if not @can_write
|
11
|
+
hash = read_file
|
12
|
+
file = Tardef::File.new(nil, nil, nil)
|
13
|
+
file.load_hash(hash["meta"])
|
14
|
+
file.filename = @filename
|
15
|
+
|
16
|
+
if hash["lists"]
|
17
|
+
hash["lists"].each do |hsh|
|
18
|
+
list = Tardef::List.new(nil, nil)
|
19
|
+
list.load_hash(hsh)
|
20
|
+
file.add_list(list)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if hash["tags"]
|
25
|
+
hash["tags"].each do |hsh|
|
26
|
+
tag = Tardef::Tag.new(nil, nil)
|
27
|
+
tag.load_hash(hsh)
|
28
|
+
file.add_tag(tag)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
if hash["tasks"]
|
33
|
+
hash["tasks"].each do |hsh|
|
34
|
+
task = Tardef::Task.new(nil, nil, nil)
|
35
|
+
task.load_hash(hsh)
|
36
|
+
file.add_task(task)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
if hash["extensions"]
|
41
|
+
hash["extensions"].each do |hsh|
|
42
|
+
ext = Tardef::Extension.new(nil, nil)
|
43
|
+
ext.load_hash(hsh)
|
44
|
+
file.add_extension(ext)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
file.schema = hash["schema"] if hash["schema"]
|
49
|
+
file
|
50
|
+
end
|
51
|
+
|
52
|
+
def write(file_object)
|
53
|
+
raise "Connector is read-only" if not @can_write
|
54
|
+
hash = file_object.to_hash
|
55
|
+
write_file(hash)
|
56
|
+
end
|
57
|
+
|
58
|
+
def set_filename(filename)
|
59
|
+
@filename = filename
|
60
|
+
end
|
61
|
+
|
62
|
+
def initialize(filename)
|
63
|
+
@filename = filename
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Tardef::Connector
|
5
|
+
class JSON < Base
|
6
|
+
def read_file
|
7
|
+
file = open(@filename)
|
8
|
+
json = ::JSON.load(file)
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_file(data)
|
12
|
+
json = ::JSON.pretty_generate(data)
|
13
|
+
::File.open(@filename, "w") { |f| f.write(json) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require "xmlsimple"
|
3
|
+
|
4
|
+
module Tardef::Connector
|
5
|
+
@can_read = false
|
6
|
+
|
7
|
+
class XML < Base
|
8
|
+
def read_file
|
9
|
+
file = open(@filename)
|
10
|
+
XmlSimple.xml_in(file)
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_file(data)
|
14
|
+
xml = XmlSimple.xml_out(data)
|
15
|
+
::File.open(@filename, "w") { |f| f.write(xml) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "open-uri"
|
2
|
+
require "yaml"
|
3
|
+
|
4
|
+
module Tardef::Connector
|
5
|
+
class YAML < Base
|
6
|
+
def read_file
|
7
|
+
file = open(@filename)
|
8
|
+
yaml = ::YAML.load(file)
|
9
|
+
end
|
10
|
+
|
11
|
+
def write_file(data)
|
12
|
+
yaml = ::YAML.dump(data)
|
13
|
+
::File.open(@filename, "w") { |f| f.write(yaml) }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Tardef
|
2
|
+
class Object < Base
|
3
|
+
attr_accessor :uid, :title, :description
|
4
|
+
end
|
5
|
+
|
6
|
+
class List < Object
|
7
|
+
attr_accessor :parent
|
8
|
+
|
9
|
+
def initialize(uid, title, description = "", parent = "", extensions = [])
|
10
|
+
@uid, @title, @description, @parent = uid, title, description, parent
|
11
|
+
@extensions = extensions
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Tag < List
|
16
|
+
end
|
17
|
+
|
18
|
+
class Task < Object
|
19
|
+
attr_accessor :created_at, :changed_at, :done_at, :due_at
|
20
|
+
attr_accessor :hidden, :list, :tags
|
21
|
+
|
22
|
+
def initialize(uid, title, created_at, description = "", changed_at = "", done_at = "", due_at = "", hidden = false, list = "", tags = [])
|
23
|
+
super()
|
24
|
+
@uid, @title, @description, @list = uid, title, description, list
|
25
|
+
@changed_at, @created_at, @done_at = changed_at, created_at, done_at
|
26
|
+
@due_at, @hidden, @tags = due_at, hidden, tags
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Tardef::Validator
|
2
|
+
class Base
|
3
|
+
def initialize
|
4
|
+
@errors = []
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class Chain
|
9
|
+
def initialize
|
10
|
+
@validators = []
|
11
|
+
@errors = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def add_validator(validator)
|
15
|
+
@validators << validator
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate(file_obj)
|
19
|
+
@errors = []
|
20
|
+
@validators.each do |validator|
|
21
|
+
@errors += validator.validate(file_obj)
|
22
|
+
end
|
23
|
+
@errors
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_errors
|
27
|
+
@errors
|
28
|
+
end
|
29
|
+
|
30
|
+
def is_valid?
|
31
|
+
!@errors.empty?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Tardef::Validator
|
2
|
+
class Extensions < Base
|
3
|
+
def validate(obj)
|
4
|
+
errors = []
|
5
|
+
extension_list = {}
|
6
|
+
obj.imports.each { |e| extension_list[e["name"]] = e }
|
7
|
+
obj = obj.to_hash
|
8
|
+
|
9
|
+
if obj["extensions"] and not obj["extensions"].empty?
|
10
|
+
obj["root"] = {"extensions" => obj["extensions"]}
|
11
|
+
end
|
12
|
+
|
13
|
+
keys = ["tasks", "lists", "tags", "root"]
|
14
|
+
keys.each do |type|
|
15
|
+
next unless obj[type]
|
16
|
+
obj[type].each do |entry|
|
17
|
+
next unless entry["extensions"]
|
18
|
+
entry["extensions"].each do |extension|
|
19
|
+
# Check that the extension is defined
|
20
|
+
unless extension_list.keys.include?(extension["name"])
|
21
|
+
errors << "Extension #{extension["name"]} is not defined"
|
22
|
+
next
|
23
|
+
end
|
24
|
+
# Check that the extension is in the right place
|
25
|
+
unless extension_list[extension["name"]]["target"] == type.chop
|
26
|
+
errors << "Extension #{extension["name"]} is not allowed as #{type} extension"
|
27
|
+
next
|
28
|
+
end
|
29
|
+
# Check for valid syntax
|
30
|
+
validator = Syntax.new(extension_list[extension["name"]]["schema"])
|
31
|
+
errors += validator.validate(extension["data"])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
errors
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Tardef::Validator
|
2
|
+
class Links < Base
|
3
|
+
def initialize
|
4
|
+
super
|
5
|
+
end
|
6
|
+
|
7
|
+
def validate(file_obj)
|
8
|
+
file_obj.lists.each do |list|
|
9
|
+
parent = list.parent
|
10
|
+
if parent and not parent.empty? and not file_obj.has_list?(parent)
|
11
|
+
@errors << "List parent #{parent} does not exist"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
file_obj.tags.each do |tag|
|
16
|
+
parent = tag.parent
|
17
|
+
if parent and not parent.empty? and not file_obj.has_tag?(parent)
|
18
|
+
@errors << "Tag parent #{parent} does not exist"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
file_obj.tasks.each do |task|
|
23
|
+
parent = task.list
|
24
|
+
if parent and not parent.empty? and not file_obj.has_list?(parent)
|
25
|
+
@errors << "Task list #{parent} does not exist"
|
26
|
+
end
|
27
|
+
task.tags.each do |tag|
|
28
|
+
@errors << "Tag #{tag} does not exist" unless file_obj.has_tag?(tag)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
@errors
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "json"
|
2
|
+
require "yaml"
|
3
|
+
require "kwalify"
|
4
|
+
require "open-uri"
|
5
|
+
|
6
|
+
module Tardef::Validator
|
7
|
+
class Syntax < Base
|
8
|
+
def initialize(schema_path)
|
9
|
+
super()
|
10
|
+
@schema_path = schema_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate(obj)
|
14
|
+
schema = ::YAML.load(open(@schema_path))
|
15
|
+
data = obj.to_hash
|
16
|
+
validator = Kwalify::Validator.new(schema)
|
17
|
+
errors = validator.validate(data)
|
18
|
+
|
19
|
+
if (errors && !errors.empty?)
|
20
|
+
for e in errors
|
21
|
+
@errors << "Schema error: [#{e.path}] #{e.message}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
@errors
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Kwalify Schema for the TARDEF Attachement Extension
|
2
|
+
# Schema Version: 1
|
3
|
+
# Schema Status: Draft
|
4
|
+
|
5
|
+
# The reminders extension can be used to attach files etc. to tasks. It may
|
6
|
+
# appear as a root level element
|
7
|
+
|
8
|
+
type: map
|
9
|
+
mapping:
|
10
|
+
"type":
|
11
|
+
type: str
|
12
|
+
required: yes
|
13
|
+
"uri":
|
14
|
+
type: str
|
15
|
+
required: yes
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# Kwalify Schema for the TARDEF Location Extension
|
2
|
+
# Schema Version: 1
|
3
|
+
# Schema Status: Draft
|
4
|
+
|
5
|
+
# The reminders extension can be used to attach locations to tasks. It may
|
6
|
+
# appear as a root level element
|
7
|
+
|
8
|
+
type: map
|
9
|
+
mapping:
|
10
|
+
"coordinates":
|
11
|
+
type: str
|
12
|
+
required: yes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Kwalify Schema for the TARDEF Reminder Extension
|
2
|
+
# Schema Version: 1
|
3
|
+
# Schema Status: Draft
|
4
|
+
|
5
|
+
# The reminders extension can be used to attach reminders to tasks. It may
|
6
|
+
# appear as a root level element
|
7
|
+
|
8
|
+
type: map
|
9
|
+
mapping:
|
10
|
+
"type":
|
11
|
+
type: str
|
12
|
+
required: yes
|
13
|
+
enum:
|
14
|
+
- "popup"
|
15
|
+
- "email"
|
16
|
+
- "other"
|
17
|
+
"time":
|
18
|
+
type: str
|
19
|
+
required: yes
|
20
|
+
pattern: &isodate /(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])?T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)??(Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?/
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Kwalify Schema for the TARDEF Task Definition Format
|
2
|
+
# Schema Version: 1
|
3
|
+
# Schema Status: Draft
|
4
|
+
# Schema URI: http://tdpsk.github.io/tardef/schema/v1-draft.yaml
|
5
|
+
|
6
|
+
# TARDEF can be used to describe tasks and other features of to dos independant
|
7
|
+
# of the application used to manage these to dos. This schema describes basic
|
8
|
+
# features, such as task lists, tags and tasks. It also provides a mechanism
|
9
|
+
# for extending the functionality using extensions.
|
10
|
+
|
11
|
+
type: map
|
12
|
+
mapping:
|
13
|
+
# --- URL to the schema file of this TARDEF file
|
14
|
+
"schema":
|
15
|
+
type: str
|
16
|
+
required: yes
|
17
|
+
|
18
|
+
# --- Meta data of the TARDEF file
|
19
|
+
"meta":
|
20
|
+
type: map
|
21
|
+
required: yes
|
22
|
+
mapping:
|
23
|
+
"title" : { type: str, required: no }
|
24
|
+
"editor" : { type: str, required: no }
|
25
|
+
"last_changed" :
|
26
|
+
type: str
|
27
|
+
required: yes
|
28
|
+
pattern: &isodate /(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[0-1]|0[1-9]|[1-2][0-9])?T(2[0-3]|[0-1][0-9]):([0-5][0-9]):([0-5][0-9])(\.[0-9]+)??(Z|[+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])?/
|
29
|
+
"imports":
|
30
|
+
type: seq
|
31
|
+
required: no
|
32
|
+
sequence:
|
33
|
+
- type: map
|
34
|
+
mapping:
|
35
|
+
"name" : { type: str, required: yes }
|
36
|
+
"schema": { type: str, required: yes }
|
37
|
+
"target":
|
38
|
+
type: str
|
39
|
+
required: yes
|
40
|
+
enum:
|
41
|
+
- root
|
42
|
+
- list
|
43
|
+
- tag
|
44
|
+
- task
|
45
|
+
|
46
|
+
# --- Task lists, aka projects
|
47
|
+
"lists":
|
48
|
+
type: seq
|
49
|
+
required: no
|
50
|
+
sequence:
|
51
|
+
- type: map
|
52
|
+
mapping:
|
53
|
+
"title" : { type: str, required: yes }
|
54
|
+
"uid" : { type: str, required: yes, unique: yes }
|
55
|
+
"description": { type: str, required: no }
|
56
|
+
"parent" : { type: str, required: no }
|
57
|
+
"due_at" : { type: str, required: no, pattern: *isodate}
|
58
|
+
"extensions" : &extensions
|
59
|
+
type: seq
|
60
|
+
required: no
|
61
|
+
sequence:
|
62
|
+
- type: map
|
63
|
+
mapping:
|
64
|
+
"name": { type: str, required: yes, unique: yes }
|
65
|
+
"data": { type: any, required: yes }
|
66
|
+
|
67
|
+
# --- Task tags, aka contexts
|
68
|
+
"tags":
|
69
|
+
type: seq
|
70
|
+
required: no
|
71
|
+
sequence:
|
72
|
+
- type: map
|
73
|
+
mapping:
|
74
|
+
"title" : { type: str, required: yes }
|
75
|
+
"uid" : { type: str, required: yes, unique: yes }
|
76
|
+
"description": { type: str, required: no }
|
77
|
+
"parent" : { type: str, required: no }
|
78
|
+
"extensions" : *extensions
|
79
|
+
|
80
|
+
# --- Tasks, aka todos
|
81
|
+
"tasks":
|
82
|
+
type: seq
|
83
|
+
required: no
|
84
|
+
sequence:
|
85
|
+
- type: map
|
86
|
+
mapping:
|
87
|
+
"title" : { type: str, required: yes }
|
88
|
+
"uid" : { type: str, required: yes, unique: yes }
|
89
|
+
"description": { type: str, required: no }
|
90
|
+
"created_at" : { type: str, required: yes, pattern: *isodate }
|
91
|
+
"changed_at" : { type: str, required: no, pattern: *isodate }
|
92
|
+
"done_at" : { type: str, required: no, pattern: *isodate }
|
93
|
+
"due_at" : { type: str, required: no, pattern: *isodate }
|
94
|
+
"hidden" : { type: bool, required: no }
|
95
|
+
"owner" : { type: str, required: no }
|
96
|
+
"list" : { type: str, required: no }
|
97
|
+
"priority" : { type: int, required: no }
|
98
|
+
"tags" :
|
99
|
+
type: seq
|
100
|
+
required: no
|
101
|
+
sequence:
|
102
|
+
- type: str
|
103
|
+
"extensions" : *extensions
|
104
|
+
|
105
|
+
# --- Root-Level extensions
|
106
|
+
"extensions": *extensions
|
data/tardef.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'tardef/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "develapp-tardef"
|
8
|
+
spec.version = Tardef::VERSION
|
9
|
+
spec.authors = ["Timo Puschkasch"]
|
10
|
+
spec.email = ["timo@puschkasch.com"]
|
11
|
+
spec.description = "Task and Related Data Exchange Format"
|
12
|
+
spec.summary = "Task and Related Data Exchange Format"
|
13
|
+
spec.homepage = "http://develapp.moskitapp.com/tardef"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rubygems-update"
|
24
|
+
|
25
|
+
spec.add_dependency "json"
|
26
|
+
spec.add_dependency "kwalify"
|
27
|
+
spec.add_dependency "xml-simple"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: develapp-tardef
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Timo Puschkasch
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubygems-update
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: json
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: kwalify
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: xml-simple
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - '>='
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
description: Task and Related Data Exchange Format
|
98
|
+
email:
|
99
|
+
- timo@puschkasch.com
|
100
|
+
executables:
|
101
|
+
- tardef
|
102
|
+
extensions: []
|
103
|
+
extra_rdoc_files: []
|
104
|
+
files:
|
105
|
+
- .gitignore
|
106
|
+
- Gemfile
|
107
|
+
- LICENSE.txt
|
108
|
+
- README.md
|
109
|
+
- Rakefile
|
110
|
+
- bin/tardef
|
111
|
+
- lib/tardef.rb
|
112
|
+
- lib/tardef/base.rb
|
113
|
+
- lib/tardef/connector/base.rb
|
114
|
+
- lib/tardef/connector/json.rb
|
115
|
+
- lib/tardef/connector/xml.rb
|
116
|
+
- lib/tardef/connector/yaml.rb
|
117
|
+
- lib/tardef/object.rb
|
118
|
+
- lib/tardef/validator/base.rb
|
119
|
+
- lib/tardef/validator/extensions.rb
|
120
|
+
- lib/tardef/validator/links.rb
|
121
|
+
- lib/tardef/validator/syntax.rb
|
122
|
+
- lib/tardef/version.rb
|
123
|
+
- schema/v1/extension/attachement.yaml
|
124
|
+
- schema/v1/extension/location.yaml
|
125
|
+
- schema/v1/extension/reminder.yaml
|
126
|
+
- schema/v1/tardef.yaml
|
127
|
+
- tardef.gemspec
|
128
|
+
homepage: http://develapp.moskitapp.com/tardef
|
129
|
+
licenses:
|
130
|
+
- MIT
|
131
|
+
metadata: {}
|
132
|
+
post_install_message:
|
133
|
+
rdoc_options: []
|
134
|
+
require_paths:
|
135
|
+
- lib
|
136
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - '>='
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - '>='
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
requirements: []
|
147
|
+
rubyforge_project:
|
148
|
+
rubygems_version: 2.0.3
|
149
|
+
signing_key:
|
150
|
+
specification_version: 4
|
151
|
+
summary: Task and Related Data Exchange Format
|
152
|
+
test_files: []
|