wlog 0.0.3 → 1.0.0
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 +4 -4
- data/.gitignore +2 -0
- data/Gemfile +1 -0
- data/README.md +72 -3
- data/Rakefile +31 -0
- data/bin/wlog +12 -6
- data/lib/wlog.rb +0 -1
- data/lib/wlog/commands/commandable.rb +9 -0
- data/lib/wlog/commands/concat_description.rb +21 -0
- data/lib/wlog/commands/innit_db.rb +22 -0
- data/lib/wlog/commands/make_csv.rb +24 -0
- data/lib/wlog/commands/new_entry.rb +16 -0
- data/lib/wlog/commands/replace_pattern.rb +21 -0
- data/lib/wlog/db_registry.rb +19 -31
- data/lib/wlog/domain/ansi_colors.rb +15 -0
- data/lib/wlog/domain/attachment.rb +80 -0
- data/lib/wlog/domain/helpers.rb +42 -0
- data/lib/wlog/domain/issue.rb +100 -0
- data/lib/wlog/domain/key_value.rb +55 -0
- data/lib/wlog/domain/log_entry.rb +100 -0
- data/lib/wlog/domain/sql_modules/attachment_sql.rb +21 -0
- data/lib/wlog/domain/sql_modules/issue_sql.rb +28 -0
- data/lib/wlog/domain/sql_modules/key_value_sql.rb +20 -0
- data/lib/wlog/domain/sql_modules/log_entry_sql.rb +35 -0
- data/lib/wlog/domain/sql_modules/polymorphic_attachments_sql.rb +24 -0
- data/lib/wlog/domain/static_configurations.rb +24 -0
- data/lib/wlog/domain/sys_config.rb +23 -0
- data/lib/wlog/sql/mono/1.sql +50 -0
- data/lib/wlog/sql/seq/.gitkeep +0 -0
- data/lib/wlog/ui/cli_interface.rb +152 -0
- data/lib/wlog/ui/commands/attach_to_issue.rb +0 -0
- data/lib/wlog/ui/commands/attach_to_log_entry.rb +11 -0
- data/lib/wlog/ui/commands/create_issue.rb +18 -0
- data/lib/wlog/ui/commands/ui_command.rb +9 -0
- data/lib/wlog/ui/issue_ui.rb +126 -0
- data/lib/wlog/version.rb +1 -1
- data/spec/key_vale_spec.rb +9 -0
- data/wlog.gemspec +6 -2
- metadata +61 -8
- data/lib/wlog/cli_interface.rb +0 -149
- data/lib/wlog/helpers.rb +0 -28
- data/lib/wlog/log_entry.rb +0 -102
- data/lib/wlog/static_configurations.rb +0 -21
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'wlog/domain/static_configurations'
|
2
|
+
|
3
|
+
module Wlog
|
4
|
+
# This contains a few helper methods that may be used by any part in the
|
5
|
+
# application.
|
6
|
+
# @author Simon Symeonidis
|
7
|
+
class Helpers
|
8
|
+
include StaticConfigurations
|
9
|
+
# Break the string to a different line
|
10
|
+
# @param string is the string that we want processed.
|
11
|
+
# @param numchars is the amount of characters max per line.
|
12
|
+
def self.break_string(string,numchars)
|
13
|
+
desc , cl = "", 0
|
14
|
+
string.split.each do |word|
|
15
|
+
wlength = word.length
|
16
|
+
if cl + wlength + 1 > numchars
|
17
|
+
cl = 0
|
18
|
+
desc.concat($/)
|
19
|
+
end
|
20
|
+
desc.concat(word).concat(" ")
|
21
|
+
cl += wlength + 1
|
22
|
+
end
|
23
|
+
desc.chomp!
|
24
|
+
desc end
|
25
|
+
|
26
|
+
# Check to see if the database exists in the DataDirectory
|
27
|
+
# @return true if exists, otherwise false
|
28
|
+
def self.database_exits?
|
29
|
+
File.exists? "#{DataDirectory}#{ARGV[0] || DefaultDb}"
|
30
|
+
end
|
31
|
+
|
32
|
+
# Check to see if DataDirectory exists
|
33
|
+
# Create the data directory if it does not exist.
|
34
|
+
def self.make_dirs!
|
35
|
+
# Does the data dir path not exist?
|
36
|
+
unless File.exists? DataDirectory
|
37
|
+
FileUtils.mkdir_p DataDirectory
|
38
|
+
end
|
39
|
+
nil end
|
40
|
+
end
|
41
|
+
end # module Wlog
|
42
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'wlog/db_registry'
|
2
|
+
require 'wlog/domain/sql_modules/issue_sql'
|
3
|
+
require 'wlog/domain/log_entry'
|
4
|
+
|
5
|
+
module Wlog
|
6
|
+
# This aggregates log entries. The total time spent on this issue is
|
7
|
+
# calculated from checking out said log entries.
|
8
|
+
# @author Simon Symeonidis
|
9
|
+
class Issue
|
10
|
+
include IssueSql
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@reported_date = Time.now
|
14
|
+
@log_entries = Array.new
|
15
|
+
@status = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.find(id)
|
19
|
+
issue = Issue.new
|
20
|
+
ret = DbRegistry.instance.execute(SelectSql, id).first
|
21
|
+
issue.quick_assign! ret
|
22
|
+
issue end
|
23
|
+
|
24
|
+
def self.find_all
|
25
|
+
arr = Array.new
|
26
|
+
DbRegistry.instance.execute(SelectAllSql).each do |row|
|
27
|
+
issue = Issue.new
|
28
|
+
issue.quick_assign! row
|
29
|
+
arr.push issue
|
30
|
+
end
|
31
|
+
arr end
|
32
|
+
|
33
|
+
def self.delete(id); DbRegistry.instance.execute(DeleteSql, id) end
|
34
|
+
|
35
|
+
def insert
|
36
|
+
DbRegistry.instance
|
37
|
+
.execute(InsertSql, @description,
|
38
|
+
@reported_date.to_i, @due_date.to_i, @status)
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete; DbRegistry.instance.execute(DeleteSql, @id) end
|
42
|
+
|
43
|
+
def update
|
44
|
+
DbRegistry.instance
|
45
|
+
.execute(UpdateSql, @description, @reported_date.to_i,
|
46
|
+
@due_date.to_i, @status, @id)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Add a log entry object to the issue
|
50
|
+
def add_log_entry(le)
|
51
|
+
@log_entries.push le
|
52
|
+
end
|
53
|
+
|
54
|
+
def quick_assign!(row)
|
55
|
+
@id, @description, @reported_date, @due_date , @status =\
|
56
|
+
row[0], row[1], Time.at(row[2]), Time.at(row[3]), row[4]
|
57
|
+
nil end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
"+ Issue ##{@id}#{$/}"\
|
61
|
+
" - Reported : #{@reported_date}#{$/}"\
|
62
|
+
" - Due : #{@due_date}#{$/}"\
|
63
|
+
" - Entries : #{@log_entries.count}#{$/}"\
|
64
|
+
" - Status : "\
|
65
|
+
"#{$/}"\
|
66
|
+
" - #{@description}"
|
67
|
+
end
|
68
|
+
|
69
|
+
def mark_started!; @status = 0 end
|
70
|
+
def mark_working!; @status = 1 end
|
71
|
+
def mark_finished!; @status = 2 end
|
72
|
+
def status_s; Statuses[@status] end
|
73
|
+
|
74
|
+
# [String] Description of the issue at hand
|
75
|
+
attr_accessor :description
|
76
|
+
|
77
|
+
# [Time] The due date of the issue
|
78
|
+
attr_accessor :due_date
|
79
|
+
|
80
|
+
# [Time] The reported date of the issue
|
81
|
+
attr_accessor :reported_date
|
82
|
+
|
83
|
+
# [Array<LogEntry>] an array containing the log entries that are specific
|
84
|
+
# to this issue
|
85
|
+
attr_accessor :log_entries
|
86
|
+
|
87
|
+
# [Fixnum] is the identifier of this object
|
88
|
+
attr_accessor :id
|
89
|
+
|
90
|
+
# [Fixnum] Status of the current issue (0 is for not started, 1 working on,
|
91
|
+
# 2 for finished)
|
92
|
+
attr_accessor :status
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
Statuses = {0 => "new", 1 => "started work", 2 => "finished"}
|
97
|
+
|
98
|
+
end # class Issue
|
99
|
+
end # module Wlog
|
100
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'wlog/db_registry'
|
2
|
+
require 'wlog/domain/sql_modules/key_value_sql'
|
3
|
+
module Wlog
|
4
|
+
# An active record that stores keys with values. Keys and values are strings.
|
5
|
+
# convert as you need them.
|
6
|
+
#
|
7
|
+
# Note the behaviour on this; it's exactly like a ruby hash, so if you store
|
8
|
+
# a string 'jon' as a key with value '12', and then you store 'jon' with value
|
9
|
+
# '42', when looking up 'jon' you will retrieve only the latter (42).
|
10
|
+
#
|
11
|
+
# @author Simon Symeonidis
|
12
|
+
class KeyValue
|
13
|
+
include KeyValueSql
|
14
|
+
|
15
|
+
# Insert a key in the storage. If exists, replace the value with new one
|
16
|
+
# @return nil
|
17
|
+
def self.put!(key, value)
|
18
|
+
if self.get(key).nil?
|
19
|
+
self.create!(key, value)
|
20
|
+
else
|
21
|
+
self.update(key, value)
|
22
|
+
end
|
23
|
+
nil end
|
24
|
+
|
25
|
+
# Get a certain value by key
|
26
|
+
# @return the value given the key. nil if not found
|
27
|
+
def self.get(key)
|
28
|
+
ret = DbRegistry.instance.execute(Select, key)
|
29
|
+
ret = ret.empty? ? nil : ret.first
|
30
|
+
end
|
31
|
+
|
32
|
+
# destroy by key
|
33
|
+
def self.destroy!(key)
|
34
|
+
DbRegistry.instance.execute(DeleteSql, key)
|
35
|
+
nil end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# We want to provide a simple interface to the kv store, so the user should
|
40
|
+
# not really care about updates
|
41
|
+
def self.update(key,value)
|
42
|
+
DbRegistry.instance.execute(UpdateSql, value, key)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Create a pair... ;)
|
46
|
+
def self.create!(key, value)
|
47
|
+
DbRegistry.instance.execute(InsertSql, key, value)
|
48
|
+
end
|
49
|
+
|
50
|
+
class << self
|
51
|
+
private :new, :allocate
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end # module Wlog
|
55
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'wlog/db_registry'
|
2
|
+
require 'wlog/domain/helpers'
|
3
|
+
require 'wlog/domain/attachment'
|
4
|
+
require 'wlog/domain/sql_modules/log_entry_sql'
|
5
|
+
|
6
|
+
module Wlog
|
7
|
+
# Author :: Simon Symeonidis
|
8
|
+
# Active Record Domain object for a log entry
|
9
|
+
class LogEntry
|
10
|
+
include LogEntrySql
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@date = Time.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find(id)
|
17
|
+
row = DbRegistry.instance.execute(Select,id).first
|
18
|
+
le = LogEntry.new
|
19
|
+
le.quick_assign!(row[0], row[1], Time.at(row[2]))
|
20
|
+
le end
|
21
|
+
|
22
|
+
def self.find_all
|
23
|
+
self.generic_find_all(SelectAll)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.find_all_by_issue_id(id)
|
27
|
+
self.generic_find_all(SelectAllByIssue, id)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Delete a log entry with a given id.
|
31
|
+
# @example Simple usage
|
32
|
+
# # Since this is a class method:
|
33
|
+
# LogEntry.delete(12)
|
34
|
+
def self.delete(id)
|
35
|
+
DbRegistry.instance.execute(DeleteSql,id)
|
36
|
+
end
|
37
|
+
|
38
|
+
# update the entry
|
39
|
+
def update
|
40
|
+
DbRegistry.instance.execute(UpdateSql,@description,@id)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Search by string to find a matching description with 'LIKE'.
|
44
|
+
def self.search_descriptions(term)
|
45
|
+
all = Array.new
|
46
|
+
DbRegistry.instance.execute(SelectDescriptionLike,"%#{term}%").each do |row|
|
47
|
+
le = LogEntry.new
|
48
|
+
le.quick_assign!(row[0], row[1], Time.at(row[2]))
|
49
|
+
all.push le
|
50
|
+
end
|
51
|
+
all end
|
52
|
+
|
53
|
+
def insert
|
54
|
+
DbRegistry.instance.execute(InsertSql, @description, @date.to_i, @issue_id)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Delete the loaded log entry currently in memory, by passing its id
|
58
|
+
def delete
|
59
|
+
self.delete(self.id)
|
60
|
+
end
|
61
|
+
|
62
|
+
def quick_assign!(id,desc,date,issue_id)
|
63
|
+
@id, @description, @date, @issue_id = id, desc, date, issue_id
|
64
|
+
end
|
65
|
+
|
66
|
+
# Print things nicely formmated no more than 80 cars (well, unless you stick
|
67
|
+
# the time in the end which is not counted for).
|
68
|
+
def to_s
|
69
|
+
str = "[#{id}] "
|
70
|
+
tmp = @description + " [#{@date.strftime("%H:%M:%S")}]"
|
71
|
+
desc = Helpers.break_string(tmp,80)
|
72
|
+
indent = " " * (id.to_s.split('').count + 5)
|
73
|
+
desc.gsub!(/#{$/}/, "#{$/}#{indent}")
|
74
|
+
str.concat(desc)
|
75
|
+
str end
|
76
|
+
|
77
|
+
# The identity field for the log entry DO
|
78
|
+
attr_accessor :id
|
79
|
+
|
80
|
+
# Text description for the log entry
|
81
|
+
attr_accessor :description
|
82
|
+
|
83
|
+
# Date the entry was created
|
84
|
+
attr_accessor :date
|
85
|
+
|
86
|
+
# The issue id (parent of this log entry)
|
87
|
+
attr_accessor :issue_id
|
88
|
+
|
89
|
+
private
|
90
|
+
def self.generic_find_all(sql, *params)
|
91
|
+
all = Array.new
|
92
|
+
DbRegistry.instance.execute(sql, *params).each do |row|
|
93
|
+
le = LogEntry.new
|
94
|
+
le.quick_assign!(row[0], row[1], Time.at(row[2]), row[3])
|
95
|
+
all.push le
|
96
|
+
end
|
97
|
+
all end
|
98
|
+
end
|
99
|
+
end # module Wlog
|
100
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Wlog
|
2
|
+
# The sql for attachments
|
3
|
+
# @author Simon Symeonidis
|
4
|
+
module AttachmentSql
|
5
|
+
# The table name
|
6
|
+
TableName = "attachments"
|
7
|
+
|
8
|
+
# Insert the file data into the database (NOTE wondering if small/big endian
|
9
|
+
# will be affecting this...)
|
10
|
+
InsertSql = "INSERT INTO #{TableName} (filename, given_name, data) "\
|
11
|
+
"values (?, ?, ?); "
|
12
|
+
|
13
|
+
# Delete by id
|
14
|
+
DeleteSql = "DELETE FROM #{TableName} WHERE discriminator = ? AND "\
|
15
|
+
"discriminator_id = ?;"
|
16
|
+
|
17
|
+
# Select an attachment given an id
|
18
|
+
SelectSql = "SELECT * FROM #{TableName} WHERE id = ? "
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Wlog
|
2
|
+
# Issue SQL
|
3
|
+
# @author Simon Symeonidis
|
4
|
+
module IssueSql
|
5
|
+
# The table name of the log entries table
|
6
|
+
TableName = "issues"
|
7
|
+
|
8
|
+
# Standard insert
|
9
|
+
InsertSql = \
|
10
|
+
"INSERT INTO #{TableName} "\
|
11
|
+
"(description, reported_date, due_date, status) "\
|
12
|
+
"values (?,?,?,?);"
|
13
|
+
# Standard delete
|
14
|
+
DeleteSql = "DELETE FROM #{TableName} WHERE id = ? ;"
|
15
|
+
|
16
|
+
# Standard update
|
17
|
+
UpdateSql = "UPDATE #{TableName} SET "\
|
18
|
+
"description = ? , reported_date = ? , due_date = ? , status = ?"\
|
19
|
+
"WHERE id = ?;"
|
20
|
+
|
21
|
+
# Select by id
|
22
|
+
SelectSql = "SELECT * FROM #{TableName} WHERE id = ? ;"
|
23
|
+
|
24
|
+
# Select all the issues
|
25
|
+
SelectAllSql = "SELECT * FROM #{TableName}; "
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Wlog
|
2
|
+
# Encapsulate the sql in only one part.
|
3
|
+
# @author Simon Symeonidis
|
4
|
+
module KeyValueSql
|
5
|
+
# The table name of the log entries table
|
6
|
+
TableName = "key_values"
|
7
|
+
|
8
|
+
# Standard insert
|
9
|
+
InsertSql = \
|
10
|
+
"INSERT INTO #{TableName} (key,value) values (?,?);"
|
11
|
+
# Standard delete
|
12
|
+
DeleteSql = "DELETE FROM #{TableName} WHERE key = ? ;"
|
13
|
+
|
14
|
+
# Standard update
|
15
|
+
UpdateSql = "UPDATE #{TableName} SET value = ? WHERE key = ?;"
|
16
|
+
|
17
|
+
# Select by key
|
18
|
+
Select = "SELECT * FROM #{TableName} WHERE key = ? ;"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Wlog
|
2
|
+
# Encapsulate the sql in only one part.
|
3
|
+
# @author Simon Symeonidis
|
4
|
+
module LogEntrySql
|
5
|
+
# The table name of the log entries table
|
6
|
+
TableName = "log_entries"
|
7
|
+
|
8
|
+
# Standard insert
|
9
|
+
InsertSql = \
|
10
|
+
"INSERT INTO #{TableName} (description,date,issue_id) values (?,?,?);"
|
11
|
+
# Standard delete
|
12
|
+
DeleteSql = "DELETE FROM #{TableName} WHERE id = ? ;"
|
13
|
+
|
14
|
+
# Standard select all
|
15
|
+
SelectAll = "SELECT * FROM #{TableName} ORDER BY date ASC;"
|
16
|
+
|
17
|
+
# Standard update
|
18
|
+
UpdateSql = "UPDATE #{TableName} SET description = ? WHERE id = ?;"
|
19
|
+
|
20
|
+
# select all with a limit
|
21
|
+
SelectAllLimit = \
|
22
|
+
"SELECT * FROM #{TableName} WHERE date >="\
|
23
|
+
" #{Time.now.to_i - 604800 - 24 * 60 * 60} ORDER BY date ASC"
|
24
|
+
|
25
|
+
# Select by id
|
26
|
+
Select = "SELECT * FROM #{TableName} WHERE id = ? ;"
|
27
|
+
|
28
|
+
# Select by id
|
29
|
+
SelectAllByIssue = "SELECT * FROM #{TableName} WHERE issue_id = ? ;"
|
30
|
+
|
31
|
+
# Select by a regex like /.../i
|
32
|
+
SelectDescriptionLike = \
|
33
|
+
"SELECT * FROM #{TableName} WHERE description LIKE ?;"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Wlog
|
2
|
+
# Sql for polymorphic attachments
|
3
|
+
# @author Simon Symeonidis
|
4
|
+
module PolymorphicAttachmentsSql
|
5
|
+
|
6
|
+
# The table name
|
7
|
+
TableName = "polymorphic_attachments"
|
8
|
+
|
9
|
+
# Select entries by discriminator name, and id
|
10
|
+
SelectSql = "SELECT * FROM #{TableName} WHERE "\
|
11
|
+
"discriminator = ? AND discriminator_id = ? "
|
12
|
+
|
13
|
+
# Insert an attachment given the current thing in hand
|
14
|
+
InsertSql = "INSERT INTO #{TableName} "\
|
15
|
+
"(discriminator, discriminator_id, attachment_id) values "\
|
16
|
+
"(? , ? , ?)"
|
17
|
+
|
18
|
+
# Delete an attachment from the attached thing
|
19
|
+
DeleteSql = "DELETE FROM #{TableName} WHERE "\
|
20
|
+
"discriminator = ? AND discriminator_id = ?"
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Wlog
|
2
|
+
# Static path data.
|
3
|
+
#
|
4
|
+
# Please follow the convention that if vars are dirs, then they end with '/'
|
5
|
+
#
|
6
|
+
# @author Simon Symeonidis
|
7
|
+
module StaticConfigurations
|
8
|
+
# The application name
|
9
|
+
AppName = "wlog"
|
10
|
+
|
11
|
+
# Absolute path to the configuration directory
|
12
|
+
ConfigDirectory = "#{ENV['HOME']}/.config/"
|
13
|
+
|
14
|
+
# Absolute path to the application directory
|
15
|
+
AppDirectory = "#{ConfigDirectory}#{AppName}/"
|
16
|
+
|
17
|
+
# Absolute path to the data directory
|
18
|
+
DataDirectory = "#{AppDirectory}data/"
|
19
|
+
|
20
|
+
# Default database name (when unspecified)
|
21
|
+
DefaultDb = "default"
|
22
|
+
end
|
23
|
+
end # module Wlog
|
24
|
+
|