nozbe-ruby 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ %w(api_call user project context action note).each do |f|
2
+ require File.dirname(__FILE__) + "/nozbe/#{f}"
3
+ end
4
+
5
+ # Nozbe module, that provides a wrapper around the Nozber-API
6
+ module Nozbe
7
+
8
+ end
9
+
@@ -0,0 +1,129 @@
1
+ module Nozbe
2
+ # Action class
3
+ # - In Nozbe, an action is a todo task.
4
+ # - It can be 'done' or not, or be your 'next' action or not.
5
+ # - It is associated with a Project and a Context
6
+ class Action
7
+ attr_accessor :id, :name, :name_show, :done, :done_time, :time, :next, :project, :context
8
+
9
+ # List all actions
10
+ # - you can specify if you want to retrieve the already-done actions
11
+ # <b>WARNING !</b>
12
+ # The Nozbe-API doesn't provide such a method, so we use multiple API calls :
13
+ # - load all projects
14
+ # - then, for each project, load all actions
15
+ def self.list(user_key, showdone = false)
16
+ Nozbe::Project.list(user_key).inject([]) { |all_actions, project|
17
+ all_actions + project.get_actions(user_key, showdone)
18
+ }
19
+ end
20
+
21
+ # List all 'next' actions
22
+ def self.list_next(user_key)
23
+ ActionsListApiCall.new(user_key, {:what => :next}).call
24
+ end
25
+
26
+ # List all actions for the given Project (using its ID)
27
+ # - you can specify if you want to retrieve the already-done actions
28
+ def self.list_for_project(user_key, project_id, showdone = false)
29
+ params = {:what => :project, :id => project_id}
30
+ params[:showdone] = "1" if showdone
31
+ ActionsListApiCall.new(user_key, params).call
32
+ end
33
+
34
+ # List all actions for the given Context (using its ID)
35
+ # - you can specify if you want to retrieve the already-done actions
36
+ def self.list_for_context(user_key, context_id, showdone = false)
37
+ params = {:what => :context, :id => context_id}
38
+ params[:showdone] = "1" if showdone
39
+ ActionsListApiCall.new(user_key, params).call
40
+ end
41
+
42
+ # Mark all given Action instances as 'done'
43
+ # - return true or false
44
+ def self.done!(user_key, actions = [])
45
+ return false if actions.empty?
46
+ ActionCheckApiCall.new(user_key, actions.collect{|action|action.id}).call
47
+ end
48
+
49
+ # Mark the current Action instance as 'done'
50
+ # - return true or false
51
+ def done!(user_key)
52
+ self.class.done!(user_key, [self])
53
+ end
54
+
55
+ # Save the current Action instance
56
+ # - used to create a new action, not to save an already existing but modified action.
57
+ # - return the instance, with its new ID set
58
+ def save!(user_key)
59
+ ActionNewApiCall.new(user_key, self).call
60
+ end
61
+ end
62
+
63
+ # This class is used internaly by the Action class
64
+ # to make the API call that list all actions
65
+ class ActionsListApiCall < Nozbe::ApiCall
66
+ action :actions
67
+ # Parse the JSON response, and return an Array of Action instances,
68
+ # or an empty array if no actions are found.
69
+ def parse(json)
70
+ actions = super(json)
71
+ return [] if actions.nil?
72
+ actions.collect do |raw_action|
73
+ action = Action.new
74
+ action.id = raw_action["id"]
75
+ action.name = raw_action["name"]
76
+ action.name_show = raw_action["name_show"]
77
+ action.done = raw_action["done"] == 1
78
+ action.done_time = raw_action["done_time"]
79
+ action.time = raw_action["time"]
80
+ action.next = raw_action["next"] == "next"
81
+ action.project = Nozbe::Project.new
82
+ action.project.id = raw_action["project_id"]
83
+ action.project.name = raw_action["project_name"]
84
+ action.context = Nozbe::Context.new
85
+ action.context.id = raw_action["context_id"]
86
+ action.context.name = raw_action["context_name"]
87
+ action.context.icon = raw_action["context_icon"]
88
+ action
89
+ end
90
+ end
91
+ end
92
+
93
+ # This class is used internaly by the Action class
94
+ # to make the API call that mark some actions as 'done'
95
+ class ActionCheckApiCall < Nozbe::ApiCall
96
+ action :check
97
+ def initialize(user_key, actions_ids = [])
98
+ super(user_key, {:ids => actions_ids})
99
+ end
100
+ # Parse the JSON response, and return true or false
101
+ def parse(json)
102
+ res = super(json)
103
+ res["response"] == "ok"
104
+ end
105
+ end
106
+
107
+ # This class is used internaly by the Action class
108
+ # to make the API call that create a new action
109
+ class ActionNewApiCall < Nozbe::ApiCall
110
+ action :newaction
111
+ def initialize(user_key, action)
112
+ params = {
113
+ :name => url_encode(action.name),
114
+ :project_id => action.project.id,
115
+ :context_id => action.context.id,
116
+ :time => action.time}
117
+ params[:next] = "true" if action.next
118
+ super(user_key, params)
119
+ @action = action
120
+ end
121
+ # Parse the JSON response, and return the action instance with its ID set
122
+ def parse(json)
123
+ res = super(json)
124
+ @action.id = res["response"]
125
+ @action
126
+ end
127
+ end
128
+
129
+ end
@@ -0,0 +1,82 @@
1
+ require 'rubygems'
2
+ require 'json'
3
+ require 'net/http'
4
+ require 'uri'
5
+
6
+ module Nozbe
7
+ # Base class for all API call
8
+ # - The Nozbe API is based on JSON responses
9
+ # - This class is inspired by the deliciousr project
10
+ class ApiCall
11
+ API_BASE_URL = 'http://www.nozbe.com:80/api'
12
+
13
+ attr_accessor :action, :parameters
14
+ attr_reader :required_parameters
15
+
16
+ # define the action to call ('new_project', 'actions', and so on...)
17
+ # - Sub-classes MUST define this !!
18
+ def self.action(action)
19
+ define_method :action do
20
+ action.to_sym
21
+ end
22
+ end
23
+
24
+ # define the user_key and all parameters for the API-call
25
+ # - Sub-classes should override this method to provide a more user-friendly signature
26
+ def initialize(key, parameters={})
27
+ @parameters = parameters
28
+ @parameters["key"] = key if key
29
+ end
30
+
31
+ # execute the API-Call, and return the parsed reponse
32
+ def call()
33
+ json = do_request()
34
+ parse(json)
35
+ end
36
+
37
+ # low-level method that do the request, and return the body response (without any parsing)
38
+ def do_request()
39
+ uri = URI.parse(API_BASE_URL + build_request_path())
40
+ response = Net::HTTP.get_response(uri)
41
+ response.body
42
+ end
43
+
44
+ # method provides a default parsing strategy for the JSON-response
45
+ # - Sub-classes should override this method to provide a specific parsing of the response
46
+ def parse(json)
47
+ JSON.parse(json) rescue nil
48
+ end
49
+
50
+ # build the request path based on the given action and built query string
51
+ def build_request_path()
52
+ path = "/#{self.action}"
53
+ if query_string = build_query_string
54
+ path += "/#{query_string}"
55
+ end
56
+ path
57
+ end
58
+
59
+ # build the query string based on the given parameters
60
+ # - the Nozbe-API convention is to use '.../paramkey-paramvalue/...'
61
+ def build_query_string()
62
+ unless parameters.nil? || parameters.empty?
63
+ query_strings = parameters.keys.sort {|a,b|
64
+ a.to_s <=> b.to_s
65
+ }.inject([]) do |result, element|
66
+ value = parameters[element]
67
+ value = value.join(";") if value.class == Array
68
+ result << "#{element.to_s}-#{value.to_s}"
69
+ end
70
+ query_strings.join('/')
71
+ else
72
+ nil
73
+ end
74
+ end
75
+
76
+ # helper method that 'url-encode' the given parameter and return it
77
+ def url_encode(param)
78
+ URI.escape(param, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
79
+ end
80
+
81
+ end
82
+ end
@@ -0,0 +1,95 @@
1
+ module Nozbe
2
+ # Context class
3
+ # - In Nozbe, a context is used to group Action (or Note) together
4
+ # - Some pre-defined contexts are already set
5
+ # - The number of user-specific contexts is limited by the Nozbe-account
6
+ class Context
7
+ DEFAULT_CONTEXT_NAME = "No context"
8
+
9
+ attr_accessor :id, :name, :icon, :body, :body_show, :count
10
+
11
+ # return the default Context instance :
12
+ # the context with its name set to DEFAULT_CONTEXT_NAME
13
+ def self.get_default_context(user_key)
14
+ get_from_name(user_key, DEFAULT_CONTEXT_NAME)
15
+ end
16
+
17
+ # return a Context instance from the given context_name
18
+ # - it may return nil if there is no matches
19
+ # <b>WARNING</b> :
20
+ # the Nozbe-API doesn't provide such a method,
21
+ # so we load all contexts and compare the names with the given name
22
+ # - the comparison is case-insensitive (use 'downcase' on all names)
23
+ def self.get_from_name(user_key, context_name)
24
+ return nil if context_name.nil?
25
+ contexts = list(user_key)
26
+ selected_contexts = contexts.select { |c| c.name.downcase == context_name.downcase }
27
+ selected_contexts.first rescue nil
28
+ end
29
+
30
+ # List all contexts
31
+ def self.list(user_key)
32
+ ContextsListApiCall.new(user_key).call
33
+ end
34
+
35
+ # load more infos (body) for the current context
36
+ def load_info(user_key)
37
+ ContextInfoApiCall.new(user_key, self).call
38
+ end
39
+
40
+ # List all actions associated with the current context
41
+ # - you can specify if you want to retrieve the already-done actions
42
+ def get_actions(user_key, showdone = false)
43
+ Nozbe::Action.list_for_context(user_key, id, showdone).collect { |action|
44
+ action.context = self
45
+ action
46
+ }
47
+ end
48
+
49
+ # List all notes associated with the current context
50
+ def get_notes(user_key)
51
+ Nozbe::Note.list_for_context(user_key, id).collect { |note|
52
+ note.context = self
53
+ note
54
+ }
55
+ end
56
+ end
57
+
58
+ # This class is used internaly by the Context class
59
+ # to make the API call that list all contexts
60
+ class ContextsListApiCall < Nozbe::ApiCall
61
+ action :contexts
62
+ # Parse the JSON response, and return an Array of Context instances
63
+ def parse(json)
64
+ contexts = super(json)
65
+ contexts.collect do |raw_context|
66
+ context = Context.new
67
+ context.id = raw_context["id"]
68
+ context.name = raw_context["name"]
69
+ context.count = raw_context["count"]
70
+ context.count = raw_context["icon"]
71
+ context
72
+ end
73
+ end
74
+ end
75
+
76
+ # This class is used internaly by the Context class
77
+ # to make the API call that retrieve the infos of a context
78
+ class ContextInfoApiCall < Nozbe::ApiCall
79
+ action :info
80
+ def initialize(user_key, context)
81
+ super(user_key, {:what => :context, :id => context.id})
82
+ @context = context
83
+ end
84
+ # Parse the JSON response, and return the context instance with its infos set
85
+ def parse(json)
86
+ raw_context = super(json)
87
+ @context.name = raw_context["name"]
88
+ @context.body = raw_context["body"]
89
+ @context.body_show = raw_context["body_show"]
90
+ @context.icon = raw_context["icon"]
91
+ @context
92
+ end
93
+ end
94
+
95
+ end
@@ -0,0 +1,84 @@
1
+ module Nozbe
2
+ # Note class
3
+ # - It is associated with a Project and a Context
4
+ class Note
5
+ attr_accessor :id, :name, :body, :body_show, :date, :project, :context
6
+
7
+ # List all notes
8
+ # <b>WARNING !</b>
9
+ # The Nozbe-API doesn't provide such a method, so we use multiple API calls :
10
+ # - load all projects
11
+ # - then, for each project, load all notes
12
+ def self.list(user_key)
13
+ Nozbe::Project.list(user_key).inject([]) { |all_notes, project|
14
+ all_notes + project.get_notes(user_key)
15
+ }
16
+ end
17
+
18
+ # List all notes for the given Project (using its ID)
19
+ def self.list_for_project(user_key, project_id)
20
+ NotesListApiCall.new(user_key, {:what => :project, :id => project_id}).call
21
+ end
22
+
23
+ # List all notes for the given Context (using its ID)
24
+ def self.list_for_context(user_key, context_id)
25
+ NotesListApiCall.new(user_key, {:what => :context, :id => context_id}).call
26
+ end
27
+
28
+ # Save the current Note instance
29
+ # - used to create a new note, not to save an already existing but modified note.
30
+ # - return the instance, with its new ID set
31
+ def save!(user_key)
32
+ NoteNewApiCall.new(user_key, self).call
33
+ end
34
+ end
35
+
36
+ # This class is used internaly by the Note class
37
+ # to make the API call that list all notes
38
+ class NotesListApiCall < Nozbe::ApiCall
39
+ action :notes
40
+ # Parse the JSON response, and return an Array of Note instances,
41
+ # or an empty array if no notes are found.
42
+ def parse(json)
43
+ notes = super(json)
44
+ return [] if notes.nil?
45
+ notes.collect do |raw_note|
46
+ note = Note.new
47
+ note.id = raw_note["id"]
48
+ note.name = raw_note["name"]
49
+ note.body = raw_note["body"]
50
+ note.body_show = raw_note["body_show"]
51
+ note.date = raw_note["date"]
52
+ note.project = Nozbe::Project.new
53
+ note.project.id = raw_note["project_id"]
54
+ note.project.name = raw_note["project_name"]
55
+ note.context = Nozbe::Context.new
56
+ note.context.id = raw_note["context_id"]
57
+ note.context.name = raw_note["context_name"]
58
+ note.context.icon = raw_note["context_icon"]
59
+ note
60
+ end
61
+ end
62
+ end
63
+
64
+ # This class is used internaly by the Note class
65
+ # to make the API call that create a new note
66
+ class NoteNewApiCall < Nozbe::ApiCall
67
+ action :newnote
68
+ def initialize(user_key, note)
69
+ super(user_key, {
70
+ :name => url_encode(note.name),
71
+ :body => url_encode(note.body),
72
+ :project_id => note.project.id,
73
+ :context_id => note.context.id,})
74
+ @note = note
75
+ end
76
+ # Parse the JSON response, and return the note instance with its ID set
77
+ def parse(json)
78
+ res = super(json)
79
+ @note.id = res["response"]
80
+ @note
81
+ end
82
+ end
83
+
84
+ end
@@ -0,0 +1,117 @@
1
+ module Nozbe
2
+ # Project class
3
+ # - In Nozbe, a project is used to group Action (or Note) together
4
+ # - The number of projects is limited by the Nozbe-account (for a free account : 5)
5
+ class Project
6
+ DEFAULT_PROJECT_NAME = "Inbox"
7
+
8
+ attr_accessor :id, :name, :body, :body_show, :count
9
+
10
+ # return the default Project instance :
11
+ # the project with its name set to DEFAULT_PROJECT_NAME
12
+ def self.get_default_project(user_key)
13
+ get_from_name(user_key, DEFAULT_PROJECT_NAME)
14
+ end
15
+
16
+ # return a Project instance from the given project_name
17
+ # - it may return nil if there is no matches
18
+ # <b>WARNING</b> :
19
+ # the Nozbe-API doesn't provide such a method,
20
+ # so we load all projects and compare the names with the given name
21
+ # - the comparison is case-insensitive (use 'downcase' on all names)
22
+ def self.get_from_name(user_key, project_name)
23
+ return nil if project_name.nil?
24
+ projects = list(user_key)
25
+ selected_projects = projects.select { |p| p.name.downcase == project_name.downcase }
26
+ selected_projects.first rescue nil
27
+ end
28
+
29
+ # List all projects
30
+ def self.list(user_key)
31
+ ProjectsListApiCall.new(user_key).call
32
+ end
33
+
34
+ # load more infos (body) for the current project
35
+ def load_info(user_key)
36
+ ProjectInfoApiCall.new(user_key, self).call
37
+ end
38
+
39
+ # List all actions associated with the current project
40
+ # - you can specify if you want to retrieve the already-done actions
41
+ def get_actions(user_key, showdone = false)
42
+ Nozbe::Action.list_for_project(user_key, id, showdone).collect { |action|
43
+ action.project = self
44
+ action
45
+ }
46
+ end
47
+
48
+ # List all notes associated with the current project
49
+ def get_notes(user_key)
50
+ Nozbe::Note.list_for_project(user_key, id).collect { |note|
51
+ note.project = self
52
+ note
53
+ }
54
+ end
55
+
56
+ # Save the current Project instance
57
+ # - used to create a new project, not to save an already existing but modified project.
58
+ # - return the instance, with its new ID set
59
+ def save!(user_key)
60
+ ProjectNewApiCall.new(user_key, self).call
61
+ end
62
+ end
63
+
64
+ # This class is used internaly by the Project class
65
+ # to make the API call that list all projects
66
+ class ProjectsListApiCall < Nozbe::ApiCall
67
+ action :projects
68
+ # Parse the JSON response, and return an Array of Project instances
69
+ def parse(json)
70
+ projects = super(json)
71
+ projects.collect do |raw_project|
72
+ project = Project.new
73
+ project.id = raw_project["id"]
74
+ project.name = raw_project["name"]
75
+ project.count = raw_project["count"]
76
+ project
77
+ end
78
+ end
79
+ end
80
+
81
+ # This class is used internaly by the Project class
82
+ # to make the API call that retrieve the infos of a project
83
+ class ProjectInfoApiCall < Nozbe::ApiCall
84
+ action :info
85
+ def initialize(user_key, project)
86
+ super(user_key, {:what => :project, :id => project.id})
87
+ @project = project
88
+ end
89
+ # Parse the JSON response, and return the project instance with its infos set
90
+ def parse(json)
91
+ raw_project = super(json)
92
+ @project.name = raw_project["name"]
93
+ @project.body = raw_project["body"]
94
+ @project.body_show = raw_project["body_show"]
95
+ @project
96
+ end
97
+ end
98
+
99
+ # This class is used internaly by the Project class
100
+ # to make the API call that create a new project
101
+ class ProjectNewApiCall < Nozbe::ApiCall
102
+ action :newproject
103
+ def initialize(user_key, project)
104
+ super(user_key, {
105
+ :name => url_encode(project.name),
106
+ :body => url_encode(project.body)})
107
+ @project = project
108
+ end
109
+ # Parse the JSON response, and return the project instance with its ID set
110
+ def parse(json)
111
+ res = super(json)
112
+ @project.id = res["response"]
113
+ @project
114
+ end
115
+ end
116
+
117
+ end
@@ -0,0 +1,42 @@
1
+ module Nozbe
2
+ # User class
3
+ # - Represents a Nozbe-User
4
+ # - Used to login (= get a user_key from the email and the password)
5
+ class User
6
+ attr_accessor :email, :password, :key
7
+
8
+ # Default constructor, that used the user email and password
9
+ def initialize(email, password)
10
+ @email = email
11
+ @password = password
12
+ @key = nil
13
+ end
14
+
15
+ # Log into Nozbe :
16
+ # - retrieve the user_key from the email and password, and return it
17
+ def login()
18
+ @key = LoginApiCall.new(self).call
19
+ end
20
+
21
+ # Is the user currently logged_in ?
22
+ # - return true if the user_key is set (= not nil)
23
+ def logged_in?()
24
+ not @key.nil?
25
+ end
26
+ end
27
+
28
+ # This class is used internaly by the User class
29
+ # to make the API call that login the user
30
+ class LoginApiCall < Nozbe::ApiCall
31
+ action :login
32
+ def initialize(user)
33
+ super(nil, {:email => user.email, :password => user.password})
34
+ end
35
+ # Parse the JSON response, and return the user_key (may be nil)
36
+ def parse(json)
37
+ res = super(json)
38
+ res["key"]
39
+ end
40
+ end
41
+
42
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: nozbe-ruby
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.2.0
7
+ date: 2008-04-21 00:00:00 +02:00
8
+ summary: Ruby wrapper around the JSON-based Nozbe API (Nozbe is a GTD webapp)
9
+ require_paths:
10
+ - lib
11
+ email: v.behar@free.fr
12
+ homepage: http://nozbe-ruby.rubyforge.org
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Vincent Behar
31
+ files:
32
+ - lib/nozbe
33
+ - lib/nozbe/user.rb
34
+ - lib/nozbe/context.rb
35
+ - lib/nozbe/note.rb
36
+ - lib/nozbe/api_call.rb
37
+ - lib/nozbe/project.rb
38
+ - lib/nozbe/action.rb
39
+ - lib/nozbe.rb
40
+ test_files: []
41
+
42
+ rdoc_options: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ executables: []
47
+
48
+ extensions: []
49
+
50
+ requirements: []
51
+
52
+ dependencies:
53
+ - !ruby/object:Gem::Dependency
54
+ name: json
55
+ version_requirement:
56
+ version_requirements: !ruby/object:Gem::Version::Requirement
57
+ requirements:
58
+ - - ">"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.0.0
61
+ version: