thingamajig 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 898bf68717745f4122521d3dc8833c6f454daa4b
4
+ data.tar.gz: ea4f2300f8d45ffb57cee09e447ab34dd95833d4
5
+ SHA512:
6
+ metadata.gz: e1499faabf11f4643d1ca7f7f06560a3078aeb16002c5859c49007a404ae1f69c288bc0e7567e6566622e8905ddd1061e8a3d85a59dad495343c107ca28c551d
7
+ data.tar.gz: c4f790028bb56dfdb0c111b2880f689af4c133032e1d708093bb2378f2d87bc5764c8c916a75cbf544236ce07e5fdec29e0b468846ae920048634ae329509843
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in thingamajig.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 David Verhasselt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,85 @@
1
+ # Thingamajig
2
+
3
+ Thingamajig offers an OOPy API to interact with a local [Things 3 Mac app](https://culturedcode.com/things/) instance. Use it to create and manipulate todos and more.
4
+
5
+ ## Usage
6
+
7
+ This README is severaly lacking in instructions. Here's some sample code that might give you an intuitive feel of how to use it:
8
+
9
+ ```ruby
10
+ # List all projects
11
+ Thingamajig.new.projects.each do |project|
12
+ puts "Found project #{project.name} with #{project.todos.count} todos"
13
+ end
14
+
15
+ # Find a project
16
+ project = Thingamajig::Project.find_by(name: "Home")
17
+
18
+ # List all todos (that have not been logged yet)
19
+ project.todos.each do |todo|
20
+ puts "Todo: #{todo.name}"
21
+ puts todo.notes
22
+ end
23
+
24
+ # List all "active" todos (i.e. showing up in Today)
25
+ project.todos(Thingamajig::Todo.predicate_active).each do |todo|
26
+ # Reschedule them to tomorrow
27
+ todo.activation_date = 1.day.from_now
28
+ end
29
+
30
+ # Create new Todo with a name and some notes
31
+ todo = project.create_todo!("Fix drainage", "Is it just clogged, or should we replace the plumbing?")
32
+
33
+ # Schedule it for a future date
34
+ todo.activation_date = 5.days.from_now
35
+
36
+ # Show it in the GUI
37
+ todo.show
38
+
39
+ # Or complete it
40
+ todo.complete!
41
+
42
+ # List all projects under the Area named "Work"
43
+ Thingamajig::Area.find_by(name: "Work").projects.flat_map do |project|
44
+ # For each project, get the todos that are active and have status "open" (not completed or cancelled)
45
+ project.todos(Thingamajig::Todo.predicate_active.and(Thingamajig::Todo.predicate_open))
46
+ end
47
+ ```
48
+
49
+ If you're tired of typing "Thingamajig" out in full, feel free to alias it:
50
+
51
+ ```ruby
52
+ Things = Thingamajig
53
+ ```
54
+
55
+ I do. Sadly RubyGems is littered with Things-related gems that haven't been updated in 8 years and don't work with Things 2, let alone Things 3, but they're still hogging all the best names. `things`, `thingies`, `things-client`, `things-rb`, ... even `thingamabob` is taken.
56
+
57
+ ## Installation
58
+
59
+ Add this line to your application's Gemfile:
60
+
61
+ ```ruby
62
+ gem 'thingamajig'
63
+ ```
64
+
65
+ And then execute:
66
+
67
+ $ bundle
68
+
69
+ Or install it yourself as:
70
+
71
+ $ gem install thingamajig
72
+
73
+ ## Development
74
+
75
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/console` for an interactive prompt that will allow you to experiment.
76
+
77
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release` to create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
78
+
79
+ ## Contributing
80
+
81
+ 1. Fork it ( https://github.com/dv/thingamajig/fork )
82
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
83
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
84
+ 4. Push to the branch (`git push origin my-new-feature`)
85
+ 5. Create a new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "thingamajig"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,24 @@
1
+ require "rb-scpt"
2
+ require "thingamajig/version"
3
+ require "thingamajig/osa_object"
4
+ require "thingamajig/area"
5
+ require "thingamajig/project"
6
+ require "thingamajig/todo"
7
+
8
+ class Thingamajig
9
+ attr :app
10
+
11
+ def osa_object
12
+ app
13
+ end
14
+
15
+ def initialize
16
+ @app ||= Appscript.app("Things3")
17
+ end
18
+
19
+ def projects
20
+ app.projects.get.map do |osa_project|
21
+ Thingamajig::Project.new(osa_project)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,41 @@
1
+ class Thingamajig
2
+ class Area < OsaObject
3
+ def self.find_by(name:)
4
+ Thingamajig::Area.new(Thingamajig.new.osa_object.areas[name])
5
+ end
6
+
7
+ # an Area's To Do list actually contains Projects & Todos, that's
8
+ # why we need some extra filtering
9
+ def todos(filter = nil)
10
+ query = todos_query
11
+ query = query.and(filter) if filter
12
+
13
+ osa_object.to_dos[query].get.map do |osa_todo|
14
+ Thingamajig::Todo.new osa_todo
15
+ end
16
+ end
17
+
18
+ def projects(filter = nil)
19
+ query = projects_query
20
+ query = query.and(filter) if filter
21
+
22
+ osa_object.to_dos[query].get.map do |osa_project|
23
+ Thingamajig::Project.new osa_project
24
+ end
25
+ end
26
+
27
+ def inspect
28
+ "#<Thingamajig::Area '#{name}'>"
29
+ end
30
+
31
+ private
32
+
33
+ def projects_query
34
+ Appscript.its.class_.eq(:project)
35
+ end
36
+
37
+ def todos_query
38
+ Appscript.its.class_.ne(:project)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,64 @@
1
+ class Thingamajig
2
+ class OsaObject
3
+ attr :osa_object
4
+
5
+ def initialize(osa_object)
6
+ @osa_object = osa_object
7
+ end
8
+
9
+ # Open in GUI
10
+ def show
11
+ osa_object.show
12
+ end
13
+
14
+ def method_missing(method_name, *arguments, &block)
15
+ valid_property, getter_or_setter, property =
16
+ parse_method_name(method_name)
17
+
18
+ if valid_property
19
+ if getter_or_setter == :getter
20
+ get_and_parse(osa_object.public_send(property))
21
+ else
22
+ osa_object.public_send(property).set(arguments.first)
23
+ end
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ def respond_to_missing?(method_name, include_private = false)
30
+ parse_method_name(method_name).first || super
31
+ end
32
+
33
+ def to_h
34
+ osa_object.properties_.get
35
+ end
36
+ alias_method :properties, :to_h
37
+
38
+ private
39
+
40
+ def parse_method_name(method_name)
41
+ method_name = String(method_name)
42
+
43
+ getter_or_setter, property =
44
+ if method_name.end_with?("=")
45
+ [:setter, method_name[0..-2]]
46
+ else
47
+ [:getter, method_name]
48
+ end
49
+
50
+ [properties.keys.include?(property.to_sym), getter_or_setter, property]
51
+ end
52
+
53
+ # OSA returns `:missing_value` for empty fields
54
+ def get_and_parse(osa_object)
55
+ result = osa_object.get
56
+
57
+ if result == :missing_value
58
+ nil
59
+ else
60
+ result
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,24 @@
1
+ class Thingamajig
2
+ class Project < OsaObject
3
+ def self.find_by(name:)
4
+ Thingamajig::Project.new(Thingamajig.new.osa_object.projects[name])
5
+ end
6
+
7
+ def todos(filter = nil)
8
+ osa_todos = osa_object.to_dos
9
+ osa_todos = osa_todos[filter] if filter
10
+
11
+ osa_todos.get.map do |osa_todo|
12
+ Thingamajig::Todo.new osa_todo
13
+ end
14
+ end
15
+
16
+ def create_todo!(name, notes)
17
+ Thingamajig::Todo.new @osa_object.make(new: :to_do, with_properties: {name: name, notes: notes})
18
+ end
19
+
20
+ def inspect
21
+ "#<Thingamajig::Project '#{name}'>"
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,71 @@
1
+ class Thingamajig
2
+ class Todo < OsaObject
3
+ def complete!
4
+ self.status = :completed
5
+ end
6
+
7
+ def completed?
8
+ self.status == :completed
9
+ end
10
+
11
+ def cancel!
12
+ self.status = :canceled
13
+ end
14
+
15
+ def canceled?
16
+ self.status == :canceled
17
+ end
18
+
19
+ def active? # meaning in "Today"
20
+ activation_date && activation_date <= Date.today.to_time
21
+ end
22
+
23
+ def activation_date=(new_activation_date)
24
+ if completed? || canceled?
25
+ self.completion_date = nil
26
+ end
27
+
28
+ osa_object.schedule(for: new_activation_date)
29
+ end
30
+
31
+ def inspect
32
+ "#<Thingamajig::Todo '#{name}'>"
33
+ end
34
+
35
+ class << self
36
+ def predicate_complete
37
+ Appscript.its.status.eq(:completed)
38
+ end
39
+
40
+ def predicate_incomplete
41
+ Appscript.its.status.ne(:completed)
42
+ end
43
+
44
+ def predicate_open
45
+ Appscript.its.status.eq(:open)
46
+ end
47
+
48
+ def predicate_active
49
+ Appscript.its.activation_date.le(Date.today)
50
+ end
51
+
52
+ def predicate_upcoming
53
+ Appscript.its.activation_date.gt(Date.today)
54
+ end
55
+
56
+ def predicate_anytime
57
+ Appscript.its.activation_date.eq(nil)
58
+ end
59
+
60
+ def completion_query(completion)
61
+ raise "Cannot have `nil` completion, use either false or true" if completion.nil?
62
+
63
+ if completion
64
+ predicate_complete
65
+ else
66
+ predicate_incomplete
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,3 @@
1
+ class Thingamajig
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'thingamajig/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "thingamajig"
8
+ spec.version = Thingamajig::VERSION
9
+ spec.authors = ["David Verhasselt"]
10
+ spec.email = ["david@crowdway.com"]
11
+
12
+ spec.summary = %q{A library providing an OOPy API for a local Things 3 Mac app}
13
+ spec.description = %q{A library providing an OOPy API for a local Things 3 Mac app, allowing you to manipulate Projects, Areas, Todos, etc}
14
+ spec.homepage = "https://github.com/dv/thingamajig"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_development_dependency "bundler", "~> 1.9"
23
+ spec.add_development_dependency "rake", "~> 10.0"
24
+
25
+ spec.add_runtime_dependency "rb-scpt"
26
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: thingamajig
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - David Verhasselt
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2018-06-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.9'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rb-scpt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A library providing an OOPy API for a local Things 3 Mac app, allowing
56
+ you to manipulate Projects, Areas, Todos, etc
57
+ email:
58
+ - david@crowdway.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".rspec"
65
+ - ".travis.yml"
66
+ - Gemfile
67
+ - LICENSE.txt
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - lib/thingamajig.rb
73
+ - lib/thingamajig/area.rb
74
+ - lib/thingamajig/osa_object.rb
75
+ - lib/thingamajig/project.rb
76
+ - lib/thingamajig/todo.rb
77
+ - lib/thingamajig/version.rb
78
+ - thingamajig.gemspec
79
+ homepage: https://github.com/dv/thingamajig
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.4.5
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: A library providing an OOPy API for a local Things 3 Mac app
103
+ test_files: []