sifttter-redux 0.3.1 → 0.3.2
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 +5 -13
- data/HISTORY.md +8 -2
- data/README.md +3 -3
- data/bin/srd +158 -155
- data/lib/sifttter_redux.rb +105 -0
- data/lib/sifttter_redux/cli_message.rb +126 -0
- data/lib/sifttter_redux/configuration.rb +122 -0
- data/lib/sifttter_redux/date_range_maker.rb +120 -0
- data/lib/sifttter_redux/dbu.rb +138 -0
- data/lib/sifttter_redux/extensions.rb +65 -0
- data/lib/sifttter_redux/os.rb +48 -0
- data/lib/sifttter_redux/sifttter.rb +98 -0
- data/lib/sifttter_redux/version.rb +3 -0
- data/{sifttter-redux.gemspec → sifttter_redux.gemspec} +4 -5
- data/test/catch_up_test.rb +51 -55
- data/test/test_helper.rb +1 -1
- metadata +21 -32
- data/lib/sifttter-redux.rb +0 -6
- data/lib/sifttter-redux/cli-message.rb +0 -135
- data/lib/sifttter-redux/config-manager.rb +0 -136
- data/lib/sifttter-redux/constants.rb +0 -15
- data/lib/sifttter-redux/date-range-maker.rb +0 -208
- data/lib/sifttter-redux/methods.rb +0 -188
- data/lib/sifttter-redux/os.rb +0 -47
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'sifttter_redux/cli_message.rb'
|
2
|
+
require 'sifttter_redux/configuration.rb'
|
3
|
+
require 'sifttter_redux/date_range_maker.rb'
|
4
|
+
require 'sifttter_redux/extensions.rb'
|
5
|
+
require 'sifttter_redux/dbu.rb'
|
6
|
+
require 'sifttter_redux/os.rb'
|
7
|
+
require 'sifttter_redux/sifttter.rb'
|
8
|
+
|
9
|
+
# ======================================================
|
10
|
+
# SifttterRedux Module
|
11
|
+
#
|
12
|
+
# Wrapper module for all other modules in this project
|
13
|
+
# ======================================================
|
14
|
+
|
15
|
+
module SifttterRedux
|
16
|
+
using CliMessage
|
17
|
+
using Configuration
|
18
|
+
|
19
|
+
# ----------------------------------------------------
|
20
|
+
# Constants
|
21
|
+
# ----------------------------------------------------
|
22
|
+
DBU_LOCAL_FILEPATH = '/usr/local/opt'
|
23
|
+
DO_REMOTE_FILEPATH = "/Apps/Day\\ One/Journal.dayone/entries"
|
24
|
+
DO_LOCAL_FILEPATH = '/tmp/dayone'
|
25
|
+
SRD_CONFIG_FILEPATH = File.join(ENV['HOME'], '.sifttter_redux')
|
26
|
+
SFT_LOCAL_FILEPATH = '/tmp/sifttter'
|
27
|
+
SFT_REMOTE_FILEPATH = '/Apps/ifttt/sifttter'
|
28
|
+
|
29
|
+
@verbose_output = true
|
30
|
+
|
31
|
+
# ----------------------------------------------------
|
32
|
+
# initialize_procedures method
|
33
|
+
#
|
34
|
+
# Initializes Sifttter Redux by downloading and
|
35
|
+
# collecting all necessary items and info.
|
36
|
+
# @return Void
|
37
|
+
# ----------------------------------------------------
|
38
|
+
def self.init
|
39
|
+
# Re-initialize the configuration data.
|
40
|
+
Configuration.reset
|
41
|
+
Configuration.add_section('sifttter_redux')
|
42
|
+
Configuration['sifttter_redux'].merge!('config_location' => Configuration.config_path)
|
43
|
+
|
44
|
+
# Run the wizard to download Dropbox Uploader.
|
45
|
+
DBU::install_wizard
|
46
|
+
|
47
|
+
# Collect other misc. preferences.
|
48
|
+
CliMessage.section_block('COLLECTING PREFERENCES...') do
|
49
|
+
pref_prompts = [
|
50
|
+
{
|
51
|
+
prompt: 'Location for downloaded Sifttter files from Dropbox',
|
52
|
+
default: SFT_LOCAL_FILEPATH,
|
53
|
+
key: 'sifttter_local_filepath',
|
54
|
+
section: 'sifttter_redux'
|
55
|
+
},
|
56
|
+
{
|
57
|
+
prompt: 'Location of Sifttter files in Dropbox',
|
58
|
+
default: SFT_REMOTE_FILEPATH,
|
59
|
+
key: 'sifttter_remote_filepath',
|
60
|
+
section: 'sifttter_redux'
|
61
|
+
},
|
62
|
+
{
|
63
|
+
prompt: 'Location for downloaded Day One files from Dropbox',
|
64
|
+
default: DO_LOCAL_FILEPATH,
|
65
|
+
key: 'dayone_local_filepath',
|
66
|
+
section: 'sifttter_redux'
|
67
|
+
},
|
68
|
+
{
|
69
|
+
prompt: 'Location of Day One files in Dropbox',
|
70
|
+
default: DO_REMOTE_FILEPATH,
|
71
|
+
key: 'dayone_remote_filepath',
|
72
|
+
section: 'sifttter_redux'
|
73
|
+
}
|
74
|
+
]
|
75
|
+
|
76
|
+
pref_prompts.each do |prompt|
|
77
|
+
pref = CliMessage.prompt(prompt[:prompt], prompt[:default])
|
78
|
+
Configuration[prompt[:section]].merge!(prompt[:key] => pref)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
Configuration.save
|
83
|
+
end
|
84
|
+
|
85
|
+
# ----------------------------------------------------
|
86
|
+
# verbose method
|
87
|
+
#
|
88
|
+
# Returns the verbosity state.
|
89
|
+
# @return Bool
|
90
|
+
# ----------------------------------------------------
|
91
|
+
def self.verbose
|
92
|
+
@verbose_output
|
93
|
+
end
|
94
|
+
|
95
|
+
# ----------------------------------------------------
|
96
|
+
# verbose= method
|
97
|
+
#
|
98
|
+
# Sets the verbosity state.
|
99
|
+
# @return Void
|
100
|
+
# ----------------------------------------------------
|
101
|
+
def self.verbose=(verbose)
|
102
|
+
@verbose_output = verbose
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module SifttterRedux
|
2
|
+
# ======================================================
|
3
|
+
# CliManager Module
|
4
|
+
# Singleton to manage common CLI interfacing
|
5
|
+
# ======================================================
|
6
|
+
module CliMessage
|
7
|
+
# ----------------------------------------------------
|
8
|
+
# error method
|
9
|
+
#
|
10
|
+
# Outputs a formatted-red error message.
|
11
|
+
# @param m The message to output
|
12
|
+
# @return Void
|
13
|
+
# ----------------------------------------------------
|
14
|
+
def self.error(m)
|
15
|
+
puts "---> ERROR: #{ m }".red
|
16
|
+
end
|
17
|
+
|
18
|
+
# ----------------------------------------------------
|
19
|
+
# info method
|
20
|
+
#
|
21
|
+
# Outputs a formatted-blue informational message.
|
22
|
+
# @param m The message to output
|
23
|
+
# @return Void
|
24
|
+
# ----------------------------------------------------
|
25
|
+
def self.info(m)
|
26
|
+
puts "---> INFO: #{ m }".blue
|
27
|
+
end
|
28
|
+
|
29
|
+
# ----------------------------------------------------
|
30
|
+
# info_block method
|
31
|
+
#
|
32
|
+
# Wraps a block in an opening and closing info message.
|
33
|
+
# @param m1 The opening message to output
|
34
|
+
# @param m2 The closing message to output
|
35
|
+
# @param multiline Whether the message should be multiline
|
36
|
+
# @return Void
|
37
|
+
# ----------------------------------------------------
|
38
|
+
def self.info_block(m1, m2 = 'Done.', multiline = false)
|
39
|
+
if multiline
|
40
|
+
info(m1)
|
41
|
+
else
|
42
|
+
print "---> INFO: #{ m1 }".blue
|
43
|
+
end
|
44
|
+
|
45
|
+
yield
|
46
|
+
|
47
|
+
if multiline
|
48
|
+
info(m2)
|
49
|
+
else
|
50
|
+
puts m2.blue
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# ----------------------------------------------------
|
55
|
+
# prompt method
|
56
|
+
#
|
57
|
+
# Outputs a prompt, collects the user's response, and
|
58
|
+
# returns it.
|
59
|
+
# @param prompt The prompt to output
|
60
|
+
# @param default The default option
|
61
|
+
# @return String
|
62
|
+
# ----------------------------------------------------
|
63
|
+
def self.prompt(prompt, default)
|
64
|
+
print "#{ prompt } [default: #{ default }]: "
|
65
|
+
choice = $stdin.gets.chomp
|
66
|
+
if choice.empty?
|
67
|
+
return default
|
68
|
+
else
|
69
|
+
return choice
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# ----------------------------------------------------
|
74
|
+
# section method
|
75
|
+
#
|
76
|
+
# Outputs a formatted-orange section message.
|
77
|
+
# @param m The message to output
|
78
|
+
# @return Void
|
79
|
+
# ----------------------------------------------------
|
80
|
+
def self.section(m)
|
81
|
+
puts "#### #{ m }".purple
|
82
|
+
end
|
83
|
+
|
84
|
+
# ----------------------------------------------------
|
85
|
+
# section_block method
|
86
|
+
#
|
87
|
+
# Wraps a block in an opening and closing section
|
88
|
+
# message.
|
89
|
+
# @param m1 The opening message to output
|
90
|
+
# @param m2 The closing message to output
|
91
|
+
# @param multiline A multiline message or not
|
92
|
+
# @return Void
|
93
|
+
# ----------------------------------------------------
|
94
|
+
def self.section_block(m, multiline = true)
|
95
|
+
if multiline
|
96
|
+
section(m)
|
97
|
+
else
|
98
|
+
print "#### #{ m }".purple
|
99
|
+
end
|
100
|
+
|
101
|
+
yield
|
102
|
+
end
|
103
|
+
|
104
|
+
# ----------------------------------------------------
|
105
|
+
# success method
|
106
|
+
#
|
107
|
+
# Outputs a formatted-green success message.
|
108
|
+
# @param m The message to output
|
109
|
+
# @return Void
|
110
|
+
# ----------------------------------------------------
|
111
|
+
def self.success(m)
|
112
|
+
puts "---> SUCCESS: #{ m }".green
|
113
|
+
end
|
114
|
+
|
115
|
+
# ----------------------------------------------------
|
116
|
+
# warning method
|
117
|
+
#
|
118
|
+
# Outputs a formatted-yellow warning message.
|
119
|
+
# @param m The message to output
|
120
|
+
# @return Void
|
121
|
+
# ----------------------------------------------------
|
122
|
+
def self.warning(m)
|
123
|
+
puts "---> WARNING: #{ m }".yellow
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SifttterRedux
|
4
|
+
# ======================================================
|
5
|
+
# Configuration Module
|
6
|
+
#
|
7
|
+
# Manages any configuration values and the flat file
|
8
|
+
# into which they get stored.
|
9
|
+
# ======================================================
|
10
|
+
module Configuration
|
11
|
+
# ----------------------------------------------------
|
12
|
+
# [] method
|
13
|
+
#
|
14
|
+
# Returns the Hash of data for a particular section.
|
15
|
+
# @param section_name The section in which to look
|
16
|
+
# @return Hash
|
17
|
+
# ----------------------------------------------------
|
18
|
+
def self.[](section_name)
|
19
|
+
@data[section_name]
|
20
|
+
end
|
21
|
+
|
22
|
+
# ----------------------------------------------------
|
23
|
+
# add_section method
|
24
|
+
#
|
25
|
+
# Creates a new section in the configuration data.
|
26
|
+
# @param section_name The section to add
|
27
|
+
# @return Void
|
28
|
+
# ----------------------------------------------------
|
29
|
+
def self.add_section(section_name)
|
30
|
+
if !self.section_exists?(section_name)
|
31
|
+
@data[section_name] = {}
|
32
|
+
else
|
33
|
+
CliMessage.warning("Can't create already-existing section: #{section_name}")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# ----------------------------------------------------
|
38
|
+
# config_path method
|
39
|
+
#
|
40
|
+
# Returns the filepath to the flat configuration file.
|
41
|
+
# @return String
|
42
|
+
# ----------------------------------------------------
|
43
|
+
def self.config_path
|
44
|
+
@config_path
|
45
|
+
end
|
46
|
+
|
47
|
+
# ----------------------------------------------------
|
48
|
+
# delete_section method
|
49
|
+
#
|
50
|
+
# Deletes a section from the configuration data.
|
51
|
+
# @param section_name The section to delete
|
52
|
+
# @return Void
|
53
|
+
# ----------------------------------------------------
|
54
|
+
def self.delete_section(section_name)
|
55
|
+
if self.section_exists?(section_name)
|
56
|
+
@data.delete(section_name)
|
57
|
+
else
|
58
|
+
CliMessage.warning("Can't delete non-existing section: #{section_name}")
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# ----------------------------------------------------
|
63
|
+
# load method
|
64
|
+
#
|
65
|
+
# Loads the configuration data (if it exists) and sets
|
66
|
+
# the filepath to the flat file.
|
67
|
+
# @param path The filepath
|
68
|
+
# @return Void
|
69
|
+
# ----------------------------------------------------
|
70
|
+
def self.load(path)
|
71
|
+
@config_path = path
|
72
|
+
|
73
|
+
if File.exists?(path)
|
74
|
+
@data = YAML.load_file(path)
|
75
|
+
else
|
76
|
+
@data = {}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# ----------------------------------------------------
|
81
|
+
# reset method
|
82
|
+
#
|
83
|
+
# Clears the configuration data.
|
84
|
+
# @return Void
|
85
|
+
# ----------------------------------------------------
|
86
|
+
def self.reset
|
87
|
+
@data = {}
|
88
|
+
end
|
89
|
+
|
90
|
+
# ----------------------------------------------------
|
91
|
+
# save method
|
92
|
+
#
|
93
|
+
# Saves the configuration data to the previously
|
94
|
+
# stored flat file.
|
95
|
+
# @return Void
|
96
|
+
# ----------------------------------------------------
|
97
|
+
def self.save
|
98
|
+
File.open(@config_path, 'w') { |f| f.write(@data.to_yaml) }
|
99
|
+
end
|
100
|
+
|
101
|
+
# ----------------------------------------------------
|
102
|
+
# section_exists? method
|
103
|
+
#
|
104
|
+
# Checks for the existance of the passed section.
|
105
|
+
# @param section_name The section to look for
|
106
|
+
# @return Bool
|
107
|
+
# ----------------------------------------------------
|
108
|
+
def self.section_exists?(section_name)
|
109
|
+
@data.key?(section_name)
|
110
|
+
end
|
111
|
+
|
112
|
+
# ----------------------------------------------------
|
113
|
+
# to_s method
|
114
|
+
#
|
115
|
+
# Method to output this Module as a String.
|
116
|
+
# @return Void
|
117
|
+
# ----------------------------------------------------
|
118
|
+
def self.to_s
|
119
|
+
puts @data
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'chronic'
|
2
|
+
|
3
|
+
module SifttterRedux
|
4
|
+
# ======================================================
|
5
|
+
# Configuration Module
|
6
|
+
#
|
7
|
+
# Manages any configuration values and the flat file
|
8
|
+
# into which they get stored.
|
9
|
+
# ======================================================
|
10
|
+
module DateRangeMaker
|
11
|
+
|
12
|
+
# ------------------------------------------------------
|
13
|
+
# last_n_days method
|
14
|
+
#
|
15
|
+
# Returns a date range for the last N days (including
|
16
|
+
# today's date if specified).
|
17
|
+
# @param num_days The number of days to look back
|
18
|
+
# @param include_today Should today be included?
|
19
|
+
# @return Range
|
20
|
+
# ------------------------------------------------------
|
21
|
+
def self.last_n_days(num_days, include_today = false)
|
22
|
+
fail ArgumentError, 'Cannot specify a negative number of days' if num_days < 0
|
23
|
+
|
24
|
+
if include_today
|
25
|
+
(Date.today - num_days..Date.today)
|
26
|
+
else
|
27
|
+
(Date.today - num_days...Date.today)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# ------------------------------------------------------
|
32
|
+
# last_n_weeks method
|
33
|
+
#
|
34
|
+
# Returns a date range for the last N weeks (including
|
35
|
+
# today's date if specified).
|
36
|
+
# @param num_days The number of weeks to look back
|
37
|
+
# @param include_today Should today be included?
|
38
|
+
# @return Range
|
39
|
+
# ------------------------------------------------------
|
40
|
+
def self.last_n_weeks(num_weeks = 0, include_today = false)
|
41
|
+
fail ArgumentError, 'Cannot specify a negative number of weeks' if num_weeks < 0
|
42
|
+
|
43
|
+
beginning_date = Date.today - Date.today.wday + 1
|
44
|
+
end_date = Date.today - Date.today.wday + 7
|
45
|
+
|
46
|
+
# We coerce the end date to be today if a date
|
47
|
+
# greater than today has been specified.
|
48
|
+
end_date = Date.today if end_date > Date.today
|
49
|
+
|
50
|
+
if include_today
|
51
|
+
(beginning_date - num_weeks * 7..end_date)
|
52
|
+
else
|
53
|
+
(beginning_date - num_weeks * 7...end_date)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# ------------------------------------------------------
|
58
|
+
# range method
|
59
|
+
#
|
60
|
+
# Returns a date range for specified start dates and
|
61
|
+
# end dates. Note that specifying an end date greater
|
62
|
+
# than today's date will force today to be the end date.
|
63
|
+
# @param start_date The start date
|
64
|
+
# @param end_date The end date
|
65
|
+
# @param options Miscellaneous options hash
|
66
|
+
# @return Range
|
67
|
+
# ------------------------------------------------------
|
68
|
+
def self.from_to(start_date, end_date, include_today = false)
|
69
|
+
fail ArgumentError, "You can't specify -t without specifying -f" if start_date.nil? && !end_date.nil?
|
70
|
+
|
71
|
+
begin
|
72
|
+
chronic_start_date = Chronic.parse(start_date).to_date
|
73
|
+
rescue
|
74
|
+
fail ArgumentError, "Invalid date provided to Chronic: #{ start_date }" unless start_date.nil?
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
begin
|
79
|
+
chronic_end_date = Chronic.parse(end_date).to_date
|
80
|
+
rescue
|
81
|
+
fail ArgumentError, "Invalid date provided to Chronic: #{ end_date }" unless end_date.nil?
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
fail ArgumentError, 'The start date must be before or equal to the end date' if chronic_end_date && chronic_start_date > chronic_end_date
|
86
|
+
|
87
|
+
unless chronic_start_date.nil?
|
88
|
+
if chronic_end_date.nil?
|
89
|
+
if include_today
|
90
|
+
(chronic_start_date..Date.today)
|
91
|
+
else
|
92
|
+
(chronic_start_date...Date.today)
|
93
|
+
end
|
94
|
+
else
|
95
|
+
(chronic_start_date..chronic_end_date)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# ------------------------------------------------------
|
101
|
+
# today method
|
102
|
+
#
|
103
|
+
# Returns a date range for today
|
104
|
+
# @return Range
|
105
|
+
# ------------------------------------------------------
|
106
|
+
def self.today
|
107
|
+
(Date.today..Date.today)
|
108
|
+
end
|
109
|
+
|
110
|
+
# ------------------------------------------------------
|
111
|
+
# yesterday method
|
112
|
+
#
|
113
|
+
# Returns a date range for yesterday
|
114
|
+
# @return Range
|
115
|
+
# ------------------------------------------------------
|
116
|
+
def self.yesterday
|
117
|
+
(Date.today - 1..Date.today - 1)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|