nozbe-ruby 0.2.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,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: