working_class 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,195 @@
1
+ # WorkingClass
2
+
3
+ WorkingClass is an human readable syntax to write tasklists.
4
+ Besides being easy to read it's fully parseable, so you can work with the tasks
5
+ in Ruby.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'working_class'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```sh
18
+ $ bundle
19
+ ```
20
+
21
+ Or install it yourself as:
22
+
23
+ ```sh
24
+ $ gem install working_class
25
+ ```
26
+
27
+ ## Usage
28
+
29
+ ### The Syntax
30
+
31
+ Keep in mind that all dates are formatted like this: `DD.MM.YYYY` or `D.M.YY`
32
+
33
+ ```
34
+ Tasklist Name
35
+ ---
36
+ [ ] My first task
37
+ [X] A finished task
38
+ [ ]{1.1.15} A task with a due date
39
+ [ ]{1.1.15}(31.1.15 12:00) A task with a date and a reminder
40
+ [ ]{1.1.15}(-1 12:00) A task with a date and a »relative« reminder
41
+ [ ]{1.1.15}(12:00) A task that will remind me at 12:00 1.1.15
42
+ ```
43
+
44
+ You see it's pretty easy to write tasks like this.
45
+
46
+ At the moment the order of date and reminder is mandatory.
47
+
48
+ So you **can't** write:
49
+
50
+ ```
51
+ My Tasklist
52
+ ---
53
+ [ ](REMINDER){DATE} My Task
54
+ ```
55
+
56
+
57
+ #### Tasklist Names
58
+
59
+ A tasklist name is written like this:
60
+
61
+ The `---` is important, don't forget it.
62
+
63
+ Every tasklist should have a name.
64
+
65
+ ```
66
+ Tasklist Name
67
+ ---
68
+
69
+ ```
70
+
71
+ #### Unfinished Tasks
72
+
73
+ Both tasks are equal, they are both not finished.
74
+
75
+ We recommend the `[ ]`, it looks much nicer.
76
+
77
+ ```
78
+ Shopping List
79
+ ---
80
+ [ ] Jeans
81
+ [] T-Shirts
82
+ ```
83
+
84
+ #### Finished Tasks
85
+
86
+ ```
87
+ Groceries List
88
+ ---
89
+ [X] Milk
90
+ [x] Bread
91
+ ```
92
+
93
+ To write a finished task you have to write a `[X]` or `[x]`. It's not important
94
+ whether you write a small x or a capital X, both characters are recognized as
95
+ a finished task.
96
+
97
+
98
+ #### Tasks with a Date
99
+
100
+ It doesn't matter if you write your dates DD.MM.YY or D.M.YY or DD.MM.YYYY
101
+ WorkingClass accepts all of those formats, as long as it is a valid date.
102
+
103
+
104
+ ```
105
+ The Party List
106
+ ---
107
+ [X]{6.2.2015} Birthday Party
108
+ [X]{13.2.15} Another Birthday Party
109
+ ```
110
+
111
+ #### Tasks with a Reminder
112
+
113
+ Every task can have a reminder.
114
+ You have several options when adding a reminder.
115
+
116
+ All times are 24h.
117
+
118
+ You can write a full date without a time and the parser will add the default
119
+ time (9:00) automatically.
120
+
121
+ ```
122
+ An even more awesome Party List
123
+ ---
124
+ [ ](31.1.15) This time of year
125
+ ```
126
+
127
+ If you already specified a date for the task you can use a relative reminder
128
+ by writing `-2`, this specifies that you want to be reminded 2 days earlier.
129
+ The parser will add the default time, if you didn't add one.
130
+
131
+ ```
132
+ The after party
133
+ ---
134
+ [ ]{2.1.15}(-2) You will have to clean up everthing.
135
+ ```
136
+
137
+ **Important:** This only works if your task has already a date.
138
+
139
+ This will not work:
140
+
141
+ ```
142
+ The after party
143
+ ---
144
+ [ ](-2) You will have to clean up everthing.
145
+ ```
146
+
147
+ So enough of that, what about the times. You can easily add a time to your
148
+ reminder
149
+
150
+ ```
151
+ My Finals
152
+ ---
153
+ [ ]{26.1.15}(15:00) English
154
+ ```
155
+
156
+ If you don't specify a relative or absolute date you will be reminded at 15:00
157
+ on the same day.
158
+
159
+
160
+ You can also combine absolute or relative dates with a time
161
+
162
+ ```
163
+ My Finals
164
+ ---
165
+ [ ]{26.1.15}(24.1.15 9:00) Don't panic.
166
+ [ ]{26.1.15}(-1 15:00) English
167
+ ```
168
+
169
+ ### The Parser
170
+
171
+ Check out the [full documentation](http://www.rubydoc.info/github/TimKaechele/WorkingClass/master)
172
+
173
+ ```ruby
174
+ require 'working_class'
175
+
176
+ string = """
177
+ My Finals
178
+ ---
179
+ [ ]{26.1.15}(15:00) English
180
+ """
181
+
182
+ WorkingClass.load(string) # => WorkingClass::Tasklist
183
+
184
+ # or if you have a file
185
+ WorkingClass.load_file('./examples/example_1.txt') # => WorkingClass::Tasklist
186
+
187
+ ```
188
+
189
+ ## Contributing
190
+
191
+ 1. Fork it ( https://github.com/TimKaechele/workingclass/fork )
192
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
193
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
194
+ 4. Push to the branch (`git push origin my-new-feature`)
195
+ 5. Create a new Pull Request
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require "rake/testtask"
4
+
5
+ Rake::TestTask.new do |task|
6
+ task.libs << %w(test lib)
7
+ task.pattern = "test/*_test.rb"
8
+ end
9
+
10
+ task :default => :test
11
+
@@ -0,0 +1,29 @@
1
+ require 'working_class/version'
2
+ require 'working_class/parser'
3
+ require 'working_class/task'
4
+ require 'working_class/tasklist'
5
+
6
+ # WorkingClass Module
7
+ #
8
+ module WorkingClass
9
+
10
+ # Loads the file from the path and returns a Tasklist
11
+ #
12
+ # @param path [String] the filepath
13
+ # @return [WorkingClass::Tasklist] the parsed Tasklist
14
+ #
15
+ def self.load_file(path)
16
+ string = File.open(path, 'r').read()
17
+ self.load(string)
18
+ end
19
+
20
+ # Parses the given string and returns a Tasklist
21
+ #
22
+ # @param string [String] the WorkingClass tasklist syntax string
23
+ # @return [WorkingClass::Tasklist] the parsed Tasklist
24
+ #
25
+ def self.load(string)
26
+ Parser.new(string).to_tasklist
27
+ end
28
+
29
+ end
@@ -0,0 +1,165 @@
1
+ require 'date'
2
+
3
+ module WorkingClass
4
+ # The actual syntax parser
5
+ #
6
+ class Parser
7
+
8
+ # Initializes a new Parser object with a given WorkingClass syntax string
9
+ #
10
+ # @param string [String] the raw string with the WorkingClass syntax
11
+ # @return [WorkingClass::Parser] a parser instance
12
+ #
13
+ def initialize(string)
14
+ @raw_string = string
15
+ @date_regex = /(?:\d{1,2}\.){2}\d{2,4}/
16
+ @time_regex = /\d{1,2}:\d{1,2}/
17
+ end
18
+
19
+ # Parses the syntax and returns an Hash with the result
20
+ #
21
+ # @return [Hash] a Hash representation of the parsed tasklist
22
+ #
23
+ def to_h
24
+ {
25
+ name: tasklist_name,
26
+ tasks_count: tasks.length,
27
+ tasks: tasks
28
+ }
29
+ end
30
+
31
+ # Parses the syntax and returns a WorkingClass::Tasklist instance
32
+ #
33
+ # @return [WorkingClass::Tasklist] a Tasklist instance of the parsed tasklist
34
+ #
35
+ def to_tasklist
36
+ tasks = Array.new
37
+ raw = self.to_h
38
+ raw[:tasks].each do |t|
39
+ task = Task.new(t[:name], t)
40
+ tasks << task
41
+ end
42
+ Tasklist.new raw[:name], tasks
43
+ end
44
+
45
+ private
46
+ def tasklist_name_regex
47
+ /(.*)\n---/
48
+ end
49
+
50
+ def task_regex
51
+ /\[(.*)\] *(?:\{(.*)\})? *(?:\((.*)\)){0,1} *(.*)/
52
+ end
53
+
54
+ def tasklist_name
55
+ @raw_string.match(tasklist_name_regex).captures.first
56
+ end
57
+
58
+ def tasks
59
+ tasks = []
60
+ @raw_string.scan(task_regex).each do |match|
61
+ task = Hash.new
62
+ task[:is_finished] = extract_is_finished(match[0])
63
+ task[:date] = extract_date(match[1])
64
+ task[:reminder] = extract_reminder(task[:date], match[2])
65
+ task[:name] = extract_name(match[3])
66
+ tasks << task
67
+ end
68
+ tasks
69
+ end
70
+
71
+ def extract_is_finished(match)
72
+ match = match.strip
73
+ if match == "x" or match == "X"
74
+ true
75
+ else
76
+ false
77
+ end
78
+ end
79
+
80
+ def extract_date(match)
81
+ if match.nil?
82
+ return nil
83
+ end
84
+
85
+ if match.scan(@date_regex)
86
+ # @todo rescue the right exception
87
+ begin
88
+ normalize_date(match)
89
+ rescue
90
+ nil
91
+ end
92
+ else
93
+ nil
94
+ end
95
+ end
96
+
97
+
98
+ def extract_name(match)
99
+ if !match.nil?
100
+ match.strip
101
+ else
102
+ ""
103
+ end
104
+ end
105
+
106
+ def normalize_date(date_string)
107
+ parts = date_string.split(".")
108
+ if parts[2].length == 2
109
+ parts[2] = "20" + parts[2]
110
+ end
111
+ parts = parts.map { |p| p.to_i }
112
+ Date.new(parts[2], parts[1], parts[0])
113
+ end
114
+
115
+ # Shame Shame
116
+ # @todo REFACTOR!!!!!1eleven!1
117
+ def extract_reminder(task_date, match)
118
+ if match.nil?
119
+ return nil
120
+ end
121
+
122
+ if match.empty? and !task_date.nil?
123
+ return DateTime.parse(task_date.to_s + " 9:00")
124
+ elsif match.empty? and task_date.nil?
125
+ return nil
126
+ end
127
+
128
+ date = nil
129
+ time = nil
130
+
131
+ absolute_date = match.scan(/(#{@date_regex})/)
132
+ relative_date = match.scan(/(-\d{1,2})/)
133
+ match_time = match.scan(/(#{@time_regex})/)
134
+
135
+ if absolute_date.empty? and (!relative_date.empty? and !task_date.nil?)
136
+ date = task_date + relative_date.flatten.first.to_i
137
+ elsif !absolute_date.empty?
138
+ # @todo rescue the right exception
139
+ begin
140
+ date = normalize_date(absolute_date.flatten.first)
141
+ rescue
142
+ date = nil
143
+ end
144
+ end
145
+
146
+ if !match_time.empty?
147
+ time = match_time
148
+ end
149
+
150
+ if !date.nil? and !time.nil?
151
+ DateTime.parse(date.to_s + " #{time}")
152
+ elsif (date.nil? and !task_date.nil?) and !time.nil?
153
+ DateTime.parse(task_date.to_s + " #{time}")
154
+ elsif !date.nil? and time.nil?
155
+ DateTime.parse(date.to_s + " 9:00")
156
+ else
157
+ return nil
158
+ end
159
+
160
+ end
161
+
162
+
163
+ end
164
+ end
165
+
@@ -0,0 +1,82 @@
1
+ module WorkingClass
2
+
3
+ # A basic represantation of a Task
4
+ #
5
+ # @attr_reader name [String] the task name
6
+ # @attr_reader is_finished [Boolean] true if the task is finished
7
+ # @attr_reader date [Date] the day the task is due
8
+ # @attr_reader reminder [DateTime] a DateTime with a reminder
9
+ class Task
10
+
11
+ attr_reader :name
12
+ attr_reader :date
13
+ attr_reader :reminder
14
+ attr_reader :is_finished
15
+
16
+ alias :is_finished? :is_finished
17
+ alias :finished? :is_finished
18
+
19
+ # Initializes a new task object with a name, and options
20
+ #
21
+ # @param name [String] the task name
22
+ # @param options [Hash] an options hash
23
+ #
24
+ # @option options [Boolean] :is_finished (false) true if the task is finished
25
+ # @option options [Date] :date (nil) the date when the task is due
26
+ # @option options [DateTime] :reminder (nil )a DateTime with a reminder
27
+ #
28
+ def initialize name, options = {}
29
+ options = {is_finished: false, date: nil, reminder: nil}.merge(options)
30
+ @name = name
31
+ @is_finished = options[:is_finished]
32
+ @date = options[:date]
33
+ @reminder = options[:reminder]
34
+ end
35
+
36
+ # Returns true if the task is upcoming
37
+ #
38
+ # A Task without a date is always upcoming.
39
+ # @todo add example
40
+ #
41
+ # A finished task is never upcoming.
42
+ # @todo add example
43
+ #
44
+ # @return [Boolean] true if the task is upcoming
45
+ def is_upcoming
46
+ if @is_finished
47
+ false
48
+ elsif !@date.nil?
49
+ Date.today <= @date
50
+ else
51
+ true
52
+ end
53
+ end
54
+
55
+ alias :is_upcoming? :is_upcoming
56
+ alias :upcoming? :is_upcoming
57
+
58
+ # Returns true if the task is due tomorrow
59
+ #
60
+ # A Task without a date is always due tomorrow.
61
+ # @todo add example
62
+ #
63
+ # A finished task is never due tomorrow.
64
+ # @todo add example
65
+ #
66
+ # @return [Boolean] true if the task is due tomorrow
67
+ def is_tomorrow
68
+ if @is_finished
69
+ false
70
+ elsif date.nil?
71
+ true
72
+ else
73
+ Date.today + 1 == @date
74
+ end
75
+ end
76
+
77
+ alias :is_tomorrow? :is_tomorrow
78
+ alias :tomorrow? :is_tomorrow
79
+
80
+
81
+ end
82
+ end