sifttter-redux 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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