waddup 0.0.1 → 0.0.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 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: