waddup 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 95fe6a3282a7513458817d10341eac6c16031560
4
- data.tar.gz: 5b23548b168517ea3cc7c85d7234828e5512fa6c
3
+ metadata.gz: 9412cd78378d88a3daf9f219baa2cc1a35fd81d7
4
+ data.tar.gz: c749fa77c45f8a397b86c90c32d56e02e0f8b637
5
5
  SHA512:
6
- metadata.gz: dd746b49772f2f4b0b807c224858f2144992e87e48663504e7095575a1ae436fd07ac5c022bfd96247195df34bc5d89e21df480b180529ae4fb59d5c404c0c2b
7
- data.tar.gz: 880b9f15d345e83edb3ea148fe8cac19a829e2a8e8978f7155d91c1c9a8b81837da3028a8827ff5527e8e7a8992877b34b372d203f37966cf21d7bda998483a6
6
+ metadata.gz: a8b44de7bd90cfeedfc321be128d67fe72ba714756dea4cb359cddf80e0e4b6eddf636e11c9880649816cfabcac17b19c26d3e57092402890ba473247e8ef108
7
+ data.tar.gz: fdc7a2ca6d6f514cad0f679b2ec4b1a3024391164642bfdf2649779e890a053492c0af2aed343de3d7cb9d23ffe5b0011453572da59f6997bbfcd686fd598afa
@@ -4,4 +4,6 @@ rvm:
4
4
  - 1.9.2
5
5
  - 1.9.3
6
6
  - 2.0.0
7
+ - rbx-18mode
8
+ - rbx-19mode
7
9
  script: bundle exec rake test
@@ -1,3 +1,7 @@
1
1
  # Changelog
2
2
 
3
- *No releases yet*
3
+ ### v0.0.2 - October 30, 2013
4
+ - Initial alpha release with Git, Apple Mail and Apple Calender sources.
5
+
6
+ ### v0.0.1 - October 9, 2013
7
+ - Placeholder release to secure Ruby gem.
data/Guardfile CHANGED
@@ -1,5 +1,6 @@
1
1
  guard :rspec do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
- watch('spec/spec_helper.rb') { 'spec' }
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ watch(%r{^spec/support/(.+)\.rb$}) { 'spec' }
5
+ watch('spec/spec_helper.rb') { 'spec' }
5
6
  end
data/README.md CHANGED
@@ -13,3 +13,71 @@ Perfect for those who have lost track of what they have worked on.
13
13
  **Supported Ruby versions: 1.8.7 or higher**
14
14
 
15
15
  Licensed under the **MIT** license, see LICENSE for more information.
16
+
17
+ ![Waddup](http://office.moonsphere.net/waddup.png?v1)
18
+
19
+
20
+ ## Installation
21
+
22
+ Waddup is available from RubyGems and can be installed through the command-line.
23
+
24
+ Fire up your favourite terminal and run:
25
+
26
+ gem install waddup
27
+
28
+ Installing on **OSX** and using the **default system Ruby**? Run:
29
+
30
+ sudo gem install waddup
31
+
32
+
33
+ ## Usage
34
+
35
+ Once installed, use the command `waddup` or its alias `sup` as follows:
36
+
37
+ waddup with git and mail since last week until yesterday 23:00
38
+
39
+ Waddup is fairly liberal in what it accepts. The keywords described below may be mixed or ommitted as desired.
40
+
41
+
42
+ ### Sources
43
+
44
+ At present, Waddup ships with three sources:
45
+
46
+ * Git `git`
47
+ * Apple Mail `mail`
48
+ * Apple Calendar `ical`
49
+
50
+ To specify one or multiple sources, use the `with`-keyword forming a regular sentence with the listed aliases:
51
+
52
+ waddup with git
53
+ waddup with git, mail and ical
54
+
55
+ When the `with`-keyword is ommitted it will default to all usable sources.
56
+
57
+
58
+ ### Start date
59
+
60
+ To specify a start date, use either `from` or `since` as a keyword:
61
+
62
+ waddup from october 29, 2013 9:00 AM
63
+ waddup since last friday
64
+
65
+ Defaults to right now if a start date is ommitted. This default is likely to change in the future.
66
+
67
+ Dates/times are liberally parsed using [Chronic](https://github.com/mojombo/chronic). A grasp of crazy inputs one can use:
68
+
69
+ * yesterday
70
+ * last night
71
+ * last winter
72
+ * 3rd wednesday in november
73
+ * may seventh '97 at three in the morning
74
+
75
+
76
+ ### End date
77
+
78
+ To specify an end date, use one of `to`, `until`, `uptil`, `upto` or `through`:
79
+
80
+ waddup upto one week ago
81
+ waddup through yesterday
82
+
83
+ Defaults to right now if an end date is ommitted.
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'bundler/gem_tasks'
2
2
  require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:test) do |spec|
5
- spec.pattern = 'spec/*.rb'
5
+ spec.pattern = 'spec/*_spec.rb'
6
6
  spec.rspec_opts = ['--color']
7
7
  end
8
8
 
data/bin/sup ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'waddup'
4
+ require 'waddup/cli'
5
+
6
+ Waddup::CLI.new.run! ARGV
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'waddup'
4
+ require 'waddup/cli'
5
+
6
+ Waddup::CLI.new.run! ARGV
@@ -1 +1,10 @@
1
+ require 'waddup/event'
2
+ require 'waddup/extension'
3
+ require 'waddup/extensions/system'
4
+ require 'waddup/extensions/applescript'
5
+ require 'waddup/registry'
6
+ require 'waddup/source'
7
+ require 'waddup/sources/apple_calendar'
8
+ require 'waddup/sources/apple_mail'
9
+ require 'waddup/sources/git'
1
10
  require 'waddup/version'
@@ -0,0 +1,76 @@
1
+ require 'chronic'
2
+
3
+ module Waddup
4
+
5
+ class CLI
6
+
7
+ attr_accessor :sources, :from, :to
8
+
9
+ KEYWORDS = {
10
+ :sources => %w[with],
11
+ :from => %w[from since],
12
+ :to => %w[to until uptil upto through]
13
+ }
14
+
15
+ KEYWORD_BOUNDARY = "(?:\\s#{KEYWORDS.values.flatten.join('|\\s')}|\\Z)"
16
+
17
+ def parse!
18
+ parse_keyword :sources do |match|
19
+ sources = match[1]
20
+ @sources = Waddup::Source.usable.select do |source|
21
+ sources.include? source::ALIAS
22
+ end
23
+ end
24
+
25
+ parse_keyword :from do |match|
26
+ @from = Chronic.parse match[1]
27
+ end
28
+
29
+ parse_keyword :to do |match|
30
+ @to = Chronic.parse match[1]
31
+ end
32
+ end
33
+
34
+ def parse_keyword(keyword, &block)
35
+ @arguments.match /(?:#{KEYWORDS[keyword].join('|')})\s(.+?)#{KEYWORD_BOUNDARY}/i, &block
36
+ end
37
+
38
+ # Parses given arguments, aggregates events and renders timesheet
39
+ def run!(arguments)
40
+ @arguments = arguments.join ' '
41
+
42
+ parse!
43
+
44
+ # Sanity checking
45
+ @sources ||= Waddup::Source.usable
46
+ @from ||= Time.now
47
+ @to ||= Time.now
48
+
49
+ # Aggregate events from all sources
50
+ events = sources.map do |source|
51
+ source.new.events from, to
52
+ end
53
+
54
+ # Sort events
55
+ events.flatten!
56
+ events.sort_by! &:at
57
+
58
+ # Group daily
59
+ days = events.group_by { |event| event.at.to_date }
60
+
61
+ # Generate timesheet
62
+ days.each_pair do |day, events|
63
+ puts
64
+ puts day.strftime('%A, %-d %B %Y')
65
+ puts
66
+ events.each do |event|
67
+ puts " #{event.at.strftime('%H:%M')} #{event.source.class::ICON} #{event.label}"
68
+ end
69
+ end
70
+
71
+ puts
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,14 @@
1
+ module Waddup
2
+
3
+ # Denotes an event obtained from a source
4
+ class Event
5
+
6
+ attr_accessor :label, :at, :until, :source
7
+
8
+ def initialize
9
+ yield self if block_given?
10
+ end
11
+
12
+ end
13
+
14
+ end
@@ -0,0 +1,4 @@
1
+ module Waddup
2
+ module Extension
3
+ end
4
+ end
@@ -0,0 +1,31 @@
1
+ module Waddup
2
+
3
+ module Extension::AppleScript
4
+ include Waddup::Extension::System
5
+
6
+ # Runs given AppleScript
7
+ #
8
+ # Options:
9
+ #
10
+ # :args (arguments to provide to the script)
11
+ # :as_ruby (whether to eval results as Ruby)
12
+ #
13
+ def applescript(script, options = {})
14
+ args = options.delete(:args) || []
15
+ arguments = args.map { |arg| " '#{arg}'" }.join
16
+ results = run("osascript -s s -e '#{script}'#{arguments}")
17
+
18
+ # TODO: This is very scary, find alternatives!
19
+ eval "[#{results[1...-1]}]" if options.delete(:as_ruby)
20
+ end
21
+
22
+ # Whether AppleScript is available
23
+ def applescript?
24
+ osx? && begin
25
+ run('osalang', :quietly => true).include? 'AppleScript'
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,31 @@
1
+ require 'rbconfig'
2
+
3
+ module Waddup
4
+
5
+ module Extension::System
6
+
7
+ # Runs given system command
8
+ #
9
+ # Options:
10
+ #
11
+ # :quietly (supresses output)
12
+ #
13
+ def run(command, options = {})
14
+ command << ' 2>&1' if options[:quietly]
15
+ `#{command}`.chomp
16
+ end
17
+
18
+ # Retrieves operating system
19
+ # See: https://github.com/celluloid/celluloid/blob/master/lib/celluloid/cpu_counter.rb
20
+ def os
21
+ @os ||= RbConfig::CONFIG['host_os'][/^[A-Za-z]+/]
22
+ end
23
+
24
+ # Whether running OSX
25
+ def osx?
26
+ os == 'darwin'
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,18 @@
1
+ module Waddup
2
+
3
+ # Automatically registers subclasses in its registry
4
+ module Registry
5
+
6
+ # Retrieves a static registry
7
+ def registry
8
+ @registry ||= []
9
+ end
10
+
11
+ # Registers given target in static registry
12
+ def inherited(target)
13
+ registry << target
14
+ end
15
+
16
+ end
17
+
18
+ end
@@ -0,0 +1,40 @@
1
+ module Waddup
2
+
3
+ # Denotes a possible source of events
4
+ # Note: Any subclasses are automatically registered
5
+ class Source
6
+ extend Waddup::Registry
7
+
8
+ # Aggregates events from this source
9
+ #
10
+ # Arguments:
11
+ #
12
+ # :from (datetime)
13
+ # :to (datetime)
14
+ #
15
+ def events(from, to)
16
+ raise NotImplementedError
17
+ end
18
+
19
+ # Delegate for convenience
20
+ def usable?
21
+ self.class.usable?
22
+ end
23
+
24
+ class << self
25
+
26
+ # Whether this source is usable
27
+ def usable?
28
+ raise NotImplementedError
29
+ end
30
+
31
+ # Only usable sources
32
+ def usable
33
+ registry.select &:usable?
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,59 @@
1
+ module Waddup
2
+
3
+ class Source::AppleCalendar < Waddup::Source
4
+ include Waddup::Extension::AppleScript
5
+ extend Waddup::Extension::AppleScript
6
+
7
+ ALIAS = 'ical'
8
+ ICON = "\xF0\x9F\x93\x85 "
9
+
10
+ EVENT_SCRIPT = %Q{
11
+ on run argv
12
+ set window_from to date (item 1 of argv)
13
+ set window_to to date (item 2 of argv)
14
+
15
+ tell application "Calendar"
16
+ set results to {}
17
+
18
+ set cdars to (events whose start date <= window_to and end date > window_from) in every calendar
19
+ repeat with cdar in cdars
20
+ repeat with evt in cdar
21
+ set end of results to {summary:summary of evt, start_date:start date of evt as string, end_date:end date of evt as string}
22
+ end repeat
23
+ end repeat
24
+
25
+ results
26
+ end tell
27
+ end run
28
+ }
29
+
30
+ # Aggregates calendar events
31
+ #
32
+ # Arguments:
33
+ #
34
+ # :from (datetime)
35
+ # :to (datetime)
36
+ #
37
+ def events(from, to)
38
+ results = applescript EVENT_SCRIPT,
39
+ :as_ruby => true,
40
+ :args => [from.strftime('%d/%m/%Y %H:%M'), to.strftime('%d/%m/%Y %H:%M')]
41
+
42
+ results.map do |result|
43
+ Waddup::Event.new do |e|
44
+ e.label = result[:summary]
45
+ e.at = DateTime.parse(result[:start_date])
46
+ e.until = DateTime.parse(result[:end_date])
47
+ e.source = self
48
+ end
49
+ end
50
+ end
51
+
52
+ # Requires AppleScript to be available
53
+ def self.usable?
54
+ applescript?
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,65 @@
1
+ module Waddup
2
+
3
+ class Source::AppleMail < Waddup::Source
4
+ include Waddup::Extension::AppleScript
5
+ extend Waddup::Extension::AppleScript
6
+
7
+ ALIAS = 'mail'
8
+ ICON = "\xE2\x9C\x89\xEF\xB8\x8F "
9
+
10
+ # Until OSX Mavericks handles Gmail's sent-mailbox correctly, resort to
11
+ # iterating through all mailboxes and identify sent messages by sender
12
+ #
13
+ # See: http://tidbits.com/article/14219
14
+ SENT_MAIL_SCRIPT = %Q{
15
+ on run argv
16
+ set window_from to date (item 1 of argv)
17
+ set window_to to date (item 2 of argv)
18
+
19
+ tell application "Mail"
20
+ set results to {}
21
+
22
+ repeat with acct in every account
23
+ set username to user name of acct
24
+ set mboxes to (messages whose sender contains username and date sent >= window_from and date sent <= window_to) in every mailbox in acct
25
+ repeat with mbox in mboxes
26
+ repeat with msg in mbox
27
+ set the end of results to {subject:subject of msg, datetime:date sent of msg as string}
28
+ end
29
+ end repeat
30
+ end repeat
31
+
32
+ results
33
+ end tell
34
+ end run
35
+ }
36
+
37
+ # Aggregates sent mail events
38
+ #
39
+ # Arguments:
40
+ #
41
+ # :from (datetime)
42
+ # :to (datetime)
43
+ #
44
+ def events(from, to)
45
+ results = applescript SENT_MAIL_SCRIPT,
46
+ :as_ruby => true,
47
+ :args => [from.strftime('%d/%m/%Y %H:%M'), to.strftime('%d/%m/%Y %H:%M')]
48
+
49
+ results.map do |result|
50
+ Waddup::Event.new do |e|
51
+ e.label = result[:subject]
52
+ e.at = DateTime.parse(result[:datetime])
53
+ e.source = self
54
+ end
55
+ end
56
+ end
57
+
58
+ # Requires AppleScript to be available
59
+ def self.usable?
60
+ applescript?
61
+ end
62
+
63
+ end
64
+
65
+ end
@@ -0,0 +1,98 @@
1
+ require 'pathname'
2
+
3
+ module Waddup
4
+
5
+ class Source::Git < Waddup::Source
6
+ include Waddup::Extension::System
7
+ extend Waddup::Extension::System
8
+
9
+ ALIAS = 'git'
10
+ ICON = "\xE2\x9C\x8F\xEF\xB8\x8F "
11
+
12
+ attr_accessor :base_path
13
+
14
+ # Retrieves author and repositories on initialization
15
+ #
16
+ # Arguments
17
+ #
18
+ # :base_path (defaults to current working directory)
19
+ #
20
+ def initialize(base_path = Dir.pwd)
21
+ @base_path = base_path
22
+ end
23
+
24
+ # Obtains author from git-config
25
+ def author
26
+ @author ||= run 'git config --get user.name'
27
+ end
28
+
29
+ # Collects repositories under base-path
30
+ def repos
31
+ @repos ||= Dir["#{base_path}/**/.git"]
32
+ end
33
+
34
+ # Aggregates events from all repositories
35
+ #
36
+ # Arguments:
37
+ #
38
+ # :from (datetime)
39
+ # :to (datetime)
40
+ #
41
+ def events(from, to)
42
+ events = repos.map do |repo|
43
+ events_for_repo from, to, repo
44
+ end
45
+ events.flatten!
46
+ end
47
+
48
+ # See: https://www.kernel.org/pub/software/scm/git/docs/git-log.html#_pretty_formats
49
+ GIT_FORMAT = '%h %ai %s'
50
+
51
+ # Pattern to extract from the above format
52
+ EXTRACT_PATTERN = /([0-9a-f]{7}) ([-0-9: ]+\+\d{4}) (.+)/i
53
+
54
+ # Aggregates events for given repository
55
+ #
56
+ # Arguments:
57
+ #
58
+ # :from (datetime)
59
+ # :to (datetime)
60
+ # :repo (path)
61
+ #
62
+ def events_for_repo(from, to, repo)
63
+ repo_label = self.class.label_for_repo repo
64
+
65
+ results = run "git --git-dir='#{repo}' log --author='#{author}' --since='#{from.iso8601}' --until='#{to.iso8601}' --format='format:#{GIT_FORMAT}'"
66
+ results.scan(EXTRACT_PATTERN).map do |hash, datetime, subject|
67
+ Waddup::Event.new do |e|
68
+ e.label = "[#{repo_label}] #{subject}"
69
+ e.at = DateTime.parse(datetime)
70
+ e.source = self
71
+ end
72
+ end
73
+ end
74
+
75
+ # Generates label for given repo path
76
+ def self.label_for_repo(repo)
77
+ path = Pathname.new(repo)
78
+ parent = path.parent
79
+
80
+ case parent.basename.to_s
81
+ when 'code', 'design'
82
+ parent = parent.parent
83
+ end
84
+
85
+ return nil if parent.root?
86
+
87
+ parent.basename.to_s
88
+ end
89
+
90
+ # Requires Git to be installed successfully
91
+ def self.usable?
92
+ run 'git --version', :quietly => true
93
+ $?.success?
94
+ end
95
+
96
+ end
97
+
98
+ end
@@ -1,5 +1,5 @@
1
1
  module Waddup
2
2
 
3
- VERSION = '0.0.1'
3
+ VERSION = '0.0.2'
4
4
 
5
5
  end
@@ -0,0 +1 @@
1
+ {{summary:"Waddup meeting", start_date:"Wednesday 16 October 2013 15:43:17", end_date:"Wednesday 16 October 2013 18:00:00"}}
@@ -0,0 +1 @@
1
+ {{subject:"E-mail regarding Waddup", datetime:"Wednesday 16 October 2013 15:43:17"}, {subject:"Another e-mail", datetime:"Wednesday 16 October 2013 17:00:12"}}
@@ -0,0 +1,2 @@
1
+ 1ddb9c9 2013-10-16 23:04:45 +0200 Spec all the things™
2
+ 19e076c 2013-10-16 23:04:16 +0200 Morph Git#author and Git#repos into lazy getters
@@ -1,10 +1,14 @@
1
- require 'simplecov'
2
- require 'coveralls'
1
+ if RUBY_VERSION >= '1.9.3'
2
+ require 'simplecov'
3
+ require 'coveralls'
3
4
 
4
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
5
- SimpleCov::Formatter::HTMLFormatter,
6
- Coveralls::SimpleCov::Formatter
7
- ]
8
- SimpleCov.start
5
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
6
+ SimpleCov::Formatter::HTMLFormatter,
7
+ Coveralls::SimpleCov::Formatter
8
+ ]
9
+ SimpleCov.start
10
+ end
9
11
 
10
12
  require 'waddup'
13
+
14
+ Dir['./spec/support/**/*.rb'].sort.each { |file| require file }
@@ -0,0 +1,4 @@
1
+ # Convenience method to retrieve a fixture
2
+ def fixture(file)
3
+ File.read "spec/fixtures/#{file}"
4
+ end
@@ -0,0 +1,47 @@
1
+ # Raised when shell operations are invoked
2
+ class ShellNotAllowedError < StandardError
3
+
4
+ def initialize(command)
5
+ msg = "Shell operation is not allowed: #{command}\n\n"
6
+ msg << "You can stub this request with the following snippet:\n\n"
7
+ msg << "stub_shell(\"#{command}\", :output => '', :exitstatus => 0)\n "
8
+ super msg
9
+ end
10
+
11
+ end
12
+
13
+ # Prevent invoking shell operations
14
+ class Object
15
+
16
+ def `(command)
17
+ raise ShellNotAllowedError, command
18
+ end
19
+
20
+ def system(command)
21
+ raise ShellNotAllowedError, command
22
+ end
23
+
24
+ # Stubs shell operations matching given command
25
+ #
26
+ # Options:
27
+ # :output (defaults to '')
28
+ # :exitstatus (defaults to 0)
29
+ #
30
+ def stub_shell(command, options = {})
31
+ output = options.delete(:output) || ''
32
+ exitstatus = options.delete(:exitstatus) || 0
33
+
34
+ block = lambda {
35
+ if exitstatus.nonzero?
36
+ Kernel.send :`, "test"
37
+ else
38
+ Kernel.send :`, "test success"
39
+ end
40
+ output
41
+ }
42
+
43
+ stub(:`).with(command).and_return &block
44
+ stub(:system).with(command).and_return &block
45
+ end
46
+
47
+ end
@@ -0,0 +1,4 @@
1
+ require 'spec_helper'
2
+
3
+ describe Waddup::Event do
4
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Waddup::Extension::System do
4
+
5
+ let(:dummy) {
6
+ Class.new do
7
+ extend Waddup::Extension::System
8
+ end
9
+ }
10
+
11
+ describe '#os' do
12
+ it 'identifies the operating system' do
13
+ stub_const('RbConfig::CONFIG', 'host_os' => 'linux')
14
+ expect(dummy.os).to eq 'linux'
15
+ end
16
+
17
+ it 'is cached' do
18
+ stub_const('RbConfig::CONFIG', 'host_os' => 'foo')
19
+ expect(dummy.os).to eq 'foo'
20
+
21
+ stub_const('RbConfig::CONFIG', 'host_os' => 'foobar')
22
+ expect(dummy.os).to eq 'foo'
23
+ end
24
+ end
25
+
26
+ describe '#osx?' do
27
+ context 'when on OSX' do
28
+ it 'returns true' do
29
+ stub_const('RbConfig::CONFIG', 'host_os' => 'darwin')
30
+ expect(dummy).to be_osx
31
+ end
32
+ end
33
+
34
+ context 'when on other operating systems' do
35
+ it 'returns false' do
36
+ stub_const('RbConfig::CONFIG', 'host_os' => 'linux')
37
+ expect(dummy).not_to be_osx
38
+ end
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Waddup::Registry do
4
+
5
+ let(:dummy) {
6
+ Class.new do
7
+ extend Waddup::Registry
8
+ end
9
+ }
10
+ let(:target) { Class.new(dummy) }
11
+
12
+ describe '#registry' do
13
+ it 'retrieves the registry' do
14
+ expect(dummy.registry).to be_an Array
15
+ end
16
+ end
17
+
18
+ describe '#register' do
19
+ it 'registers subclasses in registry' do
20
+ expect(dummy.registry).to include target
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,38 @@
1
+ require 'spec_helper'
2
+
3
+ describe Waddup::Source do
4
+
5
+ describe '#events' do
6
+ it 'has to be implemented by subclass' do
7
+ expect do
8
+ subject.events nil, nil
9
+ end.to raise_error NotImplementedError
10
+ end
11
+ end
12
+
13
+ describe '#usable?' do
14
+ it 'delegates for convenience' do
15
+ expect(described_class).to receive :usable?
16
+ subject.usable?
17
+ end
18
+ end
19
+
20
+ describe '::usable?' do
21
+ it 'has to be implemented by subclass' do
22
+ expect do
23
+ described_class.usable?
24
+ end.to raise_error NotImplementedError
25
+ end
26
+ end
27
+
28
+ describe '::usable' do
29
+ it 'retrieves usable sources' do
30
+ described_class.registry.each do |source|
31
+ source.stub(:usable?).and_return true
32
+ end
33
+
34
+ expect(described_class.usable).to be_an Array
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Waddup::Source::AppleCalendar do
4
+ let(:from) { DateTime.new 2013, 10, 16 }
5
+ let(:to) { DateTime.new 2013, 10, 17 }
6
+
7
+ describe '#events' do
8
+ before do
9
+ subject.stub_shell "osascript -s s -e '#{described_class::EVENT_SCRIPT}' '16/10/2013 00:00' '17/10/2013 00:00'",
10
+ :output => fixture('sources/apple_calendar.results')
11
+ end
12
+
13
+ it 'aggregates events' do
14
+ events = subject.events(from, to)
15
+
16
+ expect(events.first.label).to eq 'Waddup meeting'
17
+
18
+ expect(events.length).to eq 1
19
+ end
20
+ end
21
+
22
+ describe '::usable?' do
23
+ context 'when on OSX' do
24
+ before do
25
+ described_class.stub(:osx?).and_return true
26
+ end
27
+
28
+ context 'when AppleScript is available' do
29
+ before do
30
+ described_class.stub_shell 'osalang 2>&1', :output => 'AppleScript'
31
+ end
32
+
33
+ it { should be_usable }
34
+ end
35
+
36
+ context 'when AppleScript is unavailable' do
37
+ before do
38
+ described_class.stub_shell 'osalang 2>&1', :exitstatus => 1
39
+ end
40
+
41
+ it { should_not be_usable }
42
+ end
43
+ end
44
+
45
+ context 'when on other platforms' do
46
+ before do
47
+ described_class.stub(:osx?).and_return false
48
+ end
49
+
50
+ it { should_not be_usable }
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Waddup::Source::AppleMail do
4
+ let(:from) { DateTime.new 2013, 10, 16 }
5
+ let(:to) { DateTime.new 2013, 10, 17 }
6
+
7
+ describe '#events' do
8
+ before do
9
+ subject.stub_shell "osascript -s s -e '#{described_class::SENT_MAIL_SCRIPT}' '16/10/2013 00:00' '17/10/2013 00:00'",
10
+ :output => fixture('sources/apple_mail.results')
11
+ end
12
+
13
+ it 'aggregates events' do
14
+ events = subject.events(from, to)
15
+
16
+ expect(events.first.label).to eq 'E-mail regarding Waddup'
17
+ expect(events.last.label).to eq 'Another e-mail'
18
+
19
+ expect(events.length).to eq 2
20
+ end
21
+ end
22
+
23
+ describe '::usable?' do
24
+ context 'when on OSX' do
25
+ before do
26
+ described_class.stub(:osx?).and_return true
27
+ end
28
+
29
+ context 'when AppleScript is available' do
30
+ before do
31
+ described_class.stub_shell 'osalang 2>&1', :output => 'AppleScript'
32
+ end
33
+
34
+ it { should be_usable }
35
+ end
36
+
37
+ context 'when AppleScript is unavailable' do
38
+ before do
39
+ described_class.stub_shell 'osalang 2>&1', :exitstatus => 1
40
+ end
41
+
42
+ it { should_not be_usable }
43
+ end
44
+ end
45
+
46
+ context 'when on other platforms' do
47
+ before do
48
+ described_class.stub(:osx?).and_return false
49
+ end
50
+
51
+ it { should_not be_usable }
52
+ end
53
+ end
54
+
55
+ end
@@ -0,0 +1,100 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Waddup::Source::Git do
6
+ let(:from) { DateTime.new 2013, 10, 16 }
7
+ let(:to) { DateTime.new 2013, 10, 17 }
8
+
9
+ describe '#author' do
10
+ it 'obtains author from git-config' do
11
+ subject.stub(:run).and_return('John Doe')
12
+ expect(subject.author).to eq 'John Doe'
13
+ end
14
+ end
15
+
16
+ describe '#repos' do
17
+ context 'when initialized as-is' do
18
+ it 'collects repos under current working directory' do
19
+ expect(Dir).to receive(:[]).with("#{Dir.pwd}/**/.git").and_call_original
20
+ expect(subject.repos.length).to eq 1
21
+ end
22
+ end
23
+
24
+ context 'when initialized with base-path' do
25
+ before do
26
+ subject.base_path = '/projects'
27
+ end
28
+
29
+ it 'collects repos under given base-path' do
30
+ expect(Dir).to receive(:[]).with('/projects/**/.git')
31
+ subject.repos
32
+ end
33
+ end
34
+ end
35
+
36
+ describe '#events' do
37
+ it 'delegates event aggregation to #events_for_repo' do
38
+ subject.stub(:repos).and_return(['/projects/1/.git', '/projects/2/.git'])
39
+ expect(subject).to receive(:events_for_repo).with(from, to, '/projects/1/.git')
40
+ expect(subject).to receive(:events_for_repo).with(from, to, '/projects/2/.git')
41
+ subject.events from, to
42
+ end
43
+ end
44
+
45
+ describe '#events_for_repo' do
46
+ before do
47
+ subject.stub_shell "git --git-dir='/waddup/.git' log --author='John Doe' --since='2013-10-16T00:00:00+00:00' --until='2013-10-17T00:00:00+00:00' --format='format:%h %ai %s'",
48
+ :output => fixture('sources/git.log')
49
+ end
50
+
51
+ it 'aggregates events for given repo' do
52
+ subject.stub(:author).and_return('John Doe')
53
+ events = subject.events_for_repo(from, to, '/waddup/.git')
54
+
55
+ expect(events.first.label).to eq '[waddup] Spec all the things™'
56
+ expect(events.last.label).to eq '[waddup] Morph Git#author and Git#repos into lazy getters'
57
+
58
+ expect(events.length).to eq 2
59
+ end
60
+ end
61
+
62
+ describe '::label_for_repo' do
63
+ context 'with no parent folder' do
64
+ it 'returns nil' do
65
+ expect(described_class.label_for_repo '/.git').to be_nil
66
+ end
67
+ end
68
+
69
+ context 'with parent folder' do
70
+ context 'when meaningless' do
71
+ it 'labels with grandparent' do
72
+ expect(described_class.label_for_repo '/project/code/.git').to eq 'project'
73
+ end
74
+ end
75
+
76
+ it 'labels with parent' do
77
+ expect(described_class.label_for_repo '/project/.git').to eq 'project'
78
+ end
79
+ end
80
+ end
81
+
82
+ describe '::usable?' do
83
+ context 'when git is available' do
84
+ before do
85
+ described_class.stub_shell 'git --version 2>&1', :exitstatus => 0
86
+ end
87
+
88
+ it { should be_usable }
89
+ end
90
+
91
+ context 'when git is unavailable' do
92
+ before do
93
+ described_class.stub_shell 'git --version 2>&1', :exitstatus => 1
94
+ end
95
+
96
+ it { should_not be_usable }
97
+ end
98
+ end
99
+
100
+ end
@@ -20,11 +20,17 @@ Gem::Specification.new do |s|
20
20
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
21
  s.require_paths = ['lib']
22
22
 
23
- s.add_dependency 'thor', '~> 0.18.1'
23
+ s.add_dependency 'chronic'
24
24
 
25
- s.add_development_dependency 'coveralls'
26
- s.add_development_dependency 'guard-rspec'
27
25
  s.add_development_dependency 'rake'
28
26
  s.add_development_dependency 'rspec'
29
- s.add_development_dependency 'simplecov'
27
+
28
+ if RUBY_VERSION >= '1.9.3'
29
+ s.add_development_dependency 'guard'
30
+ s.add_development_dependency 'guard-rspec'
31
+ s.add_development_dependency 'listen'
32
+
33
+ s.add_development_dependency 'coveralls'
34
+ s.add_development_dependency 'simplecov'
35
+ end
30
36
  end
metadata CHANGED
@@ -1,31 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: waddup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Kurvers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-10-09 00:00:00.000000000 Z
11
+ date: 2013-10-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: thor
14
+ name: chronic
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - '>='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.18.1
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - '>='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.18.1
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: coveralls
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: rspec
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: guard
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - '>='
@@ -53,7 +81,7 @@ dependencies:
53
81
  - !ruby/object:Gem::Version
54
82
  version: '0'
55
83
  - !ruby/object:Gem::Dependency
56
- name: rake
84
+ name: listen
57
85
  requirement: !ruby/object:Gem::Requirement
58
86
  requirements:
59
87
  - - '>='
@@ -67,7 +95,7 @@ dependencies:
67
95
  - !ruby/object:Gem::Version
68
96
  version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
- name: rspec
98
+ name: coveralls
71
99
  requirement: !ruby/object:Gem::Requirement
72
100
  requirements:
73
101
  - - '>='
@@ -99,7 +127,9 @@ description: Waddup retraces your activities from arbitrary sources - such as ve
99
127
  chronological overview
100
128
  email:
101
129
  - tim@moonsphere.net
102
- executables: []
130
+ executables:
131
+ - sup
132
+ - waddup
103
133
  extensions: []
104
134
  extra_rdoc_files: []
105
135
  files:
@@ -112,10 +142,33 @@ files:
112
142
  - LICENSE.md
113
143
  - README.md
114
144
  - Rakefile
145
+ - bin/sup
146
+ - bin/waddup
115
147
  - lib/waddup.rb
116
148
  - lib/waddup/cli.rb
149
+ - lib/waddup/event.rb
150
+ - lib/waddup/extension.rb
151
+ - lib/waddup/extensions/applescript.rb
152
+ - lib/waddup/extensions/system.rb
153
+ - lib/waddup/registry.rb
154
+ - lib/waddup/source.rb
155
+ - lib/waddup/sources/apple_calendar.rb
156
+ - lib/waddup/sources/apple_mail.rb
157
+ - lib/waddup/sources/git.rb
117
158
  - lib/waddup/version.rb
159
+ - spec/fixtures/sources/apple_calendar.results
160
+ - spec/fixtures/sources/apple_mail.results
161
+ - spec/fixtures/sources/git.log
118
162
  - spec/spec_helper.rb
163
+ - spec/support/fixture.rb
164
+ - spec/support/shell_mock.rb
165
+ - spec/waddup/event_spec.rb
166
+ - spec/waddup/extensions/system_spec.rb
167
+ - spec/waddup/registry_spec.rb
168
+ - spec/waddup/source_spec.rb
169
+ - spec/waddup/sources/apple_calendar_spec.rb
170
+ - spec/waddup/sources/apple_mail_spec.rb
171
+ - spec/waddup/sources/git_spec.rb
119
172
  - waddup.gemspec
120
173
  homepage: https://github.com/timkurvers/waddup
121
174
  licenses: []
@@ -142,5 +195,17 @@ specification_version: 4
142
195
  summary: Waddup retraces your activities from arbitrary sources such as version control,
143
196
  issue tracking software and mail clients
144
197
  test_files:
198
+ - spec/fixtures/sources/apple_calendar.results
199
+ - spec/fixtures/sources/apple_mail.results
200
+ - spec/fixtures/sources/git.log
145
201
  - spec/spec_helper.rb
202
+ - spec/support/fixture.rb
203
+ - spec/support/shell_mock.rb
204
+ - spec/waddup/event_spec.rb
205
+ - spec/waddup/extensions/system_spec.rb
206
+ - spec/waddup/registry_spec.rb
207
+ - spec/waddup/source_spec.rb
208
+ - spec/waddup/sources/apple_calendar_spec.rb
209
+ - spec/waddup/sources/apple_mail_spec.rb
210
+ - spec/waddup/sources/git_spec.rb
146
211
  has_rdoc: