ntimeline 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,4 @@
1
+ == 0.1.0 2007-12-30
2
+
3
+ * Keita Yamaguchi:
4
+ * Initial release
@@ -0,0 +1,3 @@
1
+ Copyright (c) 2007 Keita Yamaguchi
2
+
3
+ NTimeLine is released under the Ruby license.
@@ -0,0 +1,31 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ config/hoe.rb
7
+ config/requirements.rb
8
+ lib/ntimeline.rb
9
+ lib/ntimeline/article.rb
10
+ lib/ntimeline/category.rb
11
+ lib/ntimeline/pager.rb
12
+ lib/ntimeline/timeline.rb
13
+ lib/ntimeline/user.rb
14
+ lib/ntimeline/version.rb
15
+ log/debug.log
16
+ script/destroy
17
+ script/generate
18
+ script/txt2html
19
+ setup.rb
20
+ spec/ntimeline_spec.rb
21
+ spec/spec.opts
22
+ spec/spec_helper.rb
23
+ tasks/deployment.rake
24
+ tasks/environment.rake
25
+ tasks/rspec.rake
26
+ tasks/website.rake
27
+ website/index.html
28
+ website/index.txt
29
+ website/javascripts/rounded_corners_lite.inc.js
30
+ website/stylesheets/screen.css
31
+ website/template.rhtml
@@ -0,0 +1,19 @@
1
+ = README
2
+
3
+ Authors:: Keita Yamaguchi(山口慶太)
4
+ Copyright:: Copyright (C) Keita Yamaguchi, 2007. All rights reserved.
5
+ License:: Ruby License
6
+
7
+ == What
8
+
9
+ NTimeLine is a wrapper library for @nifty TimeLine. You can
10
+ show/search/create/modify/delete timelines and articles.
11
+
12
+ == Links
13
+
14
+ * {@nifty}[http://www.nifty.com/]
15
+ * {@nifty TimeLine}[http://timeline.nifty.com/]
16
+ * {@nifty Web Service / TimeLine}[http://webservice.nifty.com/timeline/]
17
+ * NTimeLine
18
+ * {Website}[http://ntimeline.rubyforge.org/]
19
+ * {Rubyforge Project}[http://rubyforge.org/projects/ntimeline/]
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,83 @@
1
+ require 'ntimeline/version'
2
+
3
+ AUTHOR = 'Keita Yamaguchi' # can also be an array of Authors
4
+ EMAIL = "keita.yamaguchi@gmail.com"
5
+ DESCRIPTION = "description of gem"
6
+ GEM_NAME = 'ntimeline' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'ntimeline' # The unix name for your project
8
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = NTimeLine::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+
36
+ class Hoe
37
+ def extra_deps
38
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
39
+ @extra_deps
40
+ end
41
+ end
42
+
43
+ # Generate all the Rake tasks
44
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
45
+ hoe = Hoe.new(GEM_NAME, VERS) do |p|
46
+ p.author = AUTHOR
47
+ p.description = DESCRIPTION
48
+ p.email = EMAIL
49
+ p.summary = DESCRIPTION
50
+ p.url = HOMEPATH
51
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
52
+ p.test_globs = ["test/**/test_*.rb"]
53
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
54
+
55
+ # == Optional
56
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
57
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
58
+
59
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
60
+
61
+ end
62
+
63
+ Rake::RDocTask.new(:docs) do |rd|
64
+ rd.main = "README.txt"
65
+ rd.rdoc_dir = "doc"
66
+ Dir.glob("lib/**/*.rb") do |path| rd.rdoc_files << path end
67
+ rd.rdoc_files += ["README.txt", "History.txt", "License.txt"]
68
+ rd.title = GEM_NAME + " documentation"
69
+ rd.options += ["--opname", "index.html",
70
+ "--line-numbers",
71
+ "--inline-source",
72
+ "--accessor", "text_data=R",
73
+ "--accessor", "bool_data=R",
74
+ "--accessor", "time_data=R",
75
+ "--accessor", "int_data=R",
76
+ "--accessor", "url_data=R",
77
+ "--charset", "UTF-8"]
78
+ end
79
+
80
+ CHANGES = hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
81
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
82
+ hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
83
+ hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,17 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
16
+
17
+ require 'ntimeline'
@@ -0,0 +1,172 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "rexml/document"
4
+ require "time"
5
+
6
+ module NTimeLine
7
+ URL = URI.parse("http://api.timeline.nifty.com/api/v1")
8
+
9
+ class Base
10
+ attr_accessor :timeline_key, :updated
11
+
12
+ #
13
+ # setters
14
+ #
15
+
16
+ def self.text_data(*args)
17
+ @text_data ? @text_data += args : @text_data = args
18
+ attr_reader *args
19
+ end
20
+
21
+ def self.int_data(*args)
22
+ @int_data ? @int_data += args : @int_data = args
23
+ attr_reader *args
24
+ end
25
+
26
+ def self.bool_data(*args)
27
+ @bool_data ? @bool_data += args : @bool_data = args
28
+ attr_reader *args
29
+ end
30
+
31
+ def self.time_data(*args)
32
+ @time_data ? @time_data += args : @time_data = args
33
+ attr_reader *args
34
+ end
35
+
36
+ def self.url_data(*args)
37
+ @url_data ? @url_data += args : @url_data = args
38
+ attr_reader *args
39
+ end
40
+
41
+ #
42
+ # methods
43
+ #
44
+
45
+ def initialize(res) #:nodoc:
46
+ init(res)
47
+ end
48
+
49
+ def refresh(res) #:nodoc:
50
+ init(res)
51
+ return self
52
+ end
53
+
54
+ def init(res) #:nodoc:
55
+ self.class.instance_eval{@text_data||[]}.each do |data|
56
+ if res.elements[data.to_s]
57
+ instance_variable_set("@"+data.to_s, res.elements[data.to_s].text)
58
+ end
59
+ end
60
+ self.class.instance_eval{@int_data||[]}.each do |data|
61
+ if res.elements[data.to_s]
62
+ instance_variable_set("@"+data.to_s, res.elements[data.to_s].text.to_i)
63
+ end
64
+ end
65
+ self.class.instance_eval{@bool_data||[]}.each do |data|
66
+ if res.elements[data.to_s]
67
+ instance_variable_set("@"+data.to_s,
68
+ (res.elements[data.to_s].text == "true"))
69
+ end
70
+ end
71
+ self.class.instance_eval{@time_data||[]}.each do |data|
72
+ if res.elements[data.to_s]
73
+ instance_variable_set("@"+data.to_s,
74
+ Time.parse(res.elements[data.to_s].text))
75
+ end
76
+ end
77
+ self.class.instance_eval{@url_data||[]}.each do |data|
78
+ if res.elements[data.to_s].text
79
+ instance_variable_set("@"+data.to_s,
80
+ URI.parse(res.elements[data.to_s].text))
81
+ end
82
+ end
83
+ end
84
+
85
+ # Send a request message to the server.
86
+ # path:: relative path from http://api.timeline.nifty.com/api/v1
87
+ # params:: parameters hash table
88
+ # target:: class or object
89
+ def self.request(path, params={}, target = self)
90
+ req = Net::HTTP::Post.new(URL.path + path)
91
+ data = params.inject(Hash.new) do |data, (key, val)|
92
+ val.kind_of?(Time) ? data[key.to_s] = val.iso8601 : data[key.to_s] = val
93
+ data
94
+ end
95
+ req.set_form_data data
96
+ case res = Net::HTTP.new(URL.host).request(req)
97
+ when Net::HTTPSuccess
98
+ doc = REXML::Document.new(res.body)
99
+ obj = target.kind_of?(Class) ? target.new(doc) : target.refresh(doc)
100
+ obj.request_params = params if obj.kind_of?(NTimeLine::Pager)
101
+ obj.timeline_key = params[:timeline_key] if params.has_key?(:timeline_key)
102
+ return obj
103
+ when Net::HTTPBadRequest
104
+ raise BadRequestError.new(REXML::Document.new(res.body))
105
+ when Net::HTTPForbidden
106
+ p res.body
107
+ raise ForbiddenError.new(REXML::Document.new(res.body))
108
+ else
109
+ raise ResponseError.new(res)
110
+ end
111
+ end
112
+
113
+ # Same as request but need timeline_key.
114
+ # path:: relative path from http://api.timeline.nifty.com/api/v1
115
+ # params:: parameters hash table
116
+ # target:: class or object
117
+ def self.request_with_key(path, params={}, target=self)
118
+ # check timeline_key
119
+ unless params.has_key?(:timeline_key)
120
+ raise ArgumentError, "There is not :timeline_key in params"
121
+ end
122
+ # request
123
+ request(path, params, target)
124
+ end
125
+
126
+ # Same as request.
127
+ def request(path, params={}, target = self.class)
128
+ self.class.request(path, params, target)
129
+ end
130
+
131
+ # Same as request_with_key.
132
+ def request_with_key(path, params={}, target = self.class)
133
+ self.class.request_with_key(path, params, target)
134
+ end
135
+ end
136
+
137
+ # Succeeded is a dummy class for successful response.
138
+ class Succeeded < Base
139
+ def initialize(doc); end
140
+ end
141
+
142
+ #
143
+ # EXCEPTIONS
144
+ #
145
+
146
+ class Error < StandardError; end
147
+
148
+ class ResponseError < Error
149
+ attr_reader :response
150
+ def initialize(response)
151
+ @response = response
152
+ end
153
+ end
154
+
155
+ class BadRequestError < Error
156
+ def initialize(res)
157
+ @response = res
158
+ @code = res.elements["/response/status/code"].text.to_i
159
+ @message = res.elements["/response/status/message"].text
160
+ end
161
+
162
+ def message
163
+ self.class.name + "(code:" + @code.to_s + "): message=" + @message
164
+ end
165
+ end
166
+ end
167
+
168
+ require 'ntimeline/article'
169
+ require 'ntimeline/timeline'
170
+ require 'ntimeline/pager'
171
+ require 'ntimeline/user'
172
+ require 'ntimeline/version'
@@ -0,0 +1,146 @@
1
+ module NTimeLine
2
+
3
+ # Ariticle is a class for an event article.
4
+ class Article < Base
5
+ text_data :id, :title, :description, :owner
6
+ int_data :grade
7
+ time_data :start_time, :end_time, :updated_at, :created_at
8
+ url_data :image, :link
9
+ attr_reader :related_links
10
+
11
+ def init(doc) #:nodoc:
12
+ elt = nil
13
+ if doc.kind_of?(REXML::Document)
14
+ unless elt = doc.root.elements["/response/result/article"]
15
+ raise ArgumentError, doc
16
+ end
17
+ else
18
+ elt = doc
19
+ end
20
+ super(elt)
21
+ @related_links = []
22
+ elt.elements["related_links"].each_element("url") do |url|
23
+ @related_links << url.text
24
+ end
25
+ end
26
+
27
+ def ==(other) #:nodoc:
28
+ @id == other.id
29
+ end
30
+
31
+ # Fetch an article by id.
32
+ # id:: article id
33
+ # params:: See http://webservice.nifty.com/timeline/v1/articles/show.htm for details.
34
+ # - :timeline_key
35
+ def self.show(id, params={})
36
+ # check timeline_key
37
+ unless params.has_key?(:timeline_key)
38
+ raise ArgumentError, "There is not :timeline_key in params."
39
+ end
40
+ # send
41
+ request("/articles/show/#{id}", params)
42
+ end
43
+
44
+ # Create a new article.
45
+ # params:: See http://webservice.nifty.com/timeline/v1/articles/create.htm for details.
46
+ # - :timeline_key (required)
47
+ # - :timeline_id (required)
48
+ # - :title (required)
49
+ # - :description (required)
50
+ # - :start_time (required)
51
+ # - :end_time (required)
52
+ # - :grade (required)
53
+ # - :link (FIXME: URI or array of it)
54
+ # - :image (FIXME: file or string)
55
+ # - :image_type
56
+ def self.create(params)
57
+ # check params
58
+ unless params.include?(:timeline_id) &&
59
+ params.include?(:title) &&
60
+ params.include?(:description) &&
61
+ params.include?(:start_time) &&
62
+ params.include?(:end_time) &&
63
+ params.include?(:grade)
64
+ raise ArgumentError, <<-ERR
65
+ Required parameters(:title, :description, :start_time, :end_time, :grade) are missing.
66
+ ERR
67
+ end
68
+
69
+ # request
70
+ request_with_key("/articles/create", params)
71
+ end
72
+
73
+ # Update an article.
74
+ # id:: article id
75
+ # params:: see http://webservice.nifty.com/timeline/v1/articles/create.htm for details
76
+ # - :title
77
+ # - :description
78
+ # - :start_time
79
+ # - :end_time
80
+ # - :grade
81
+ # - :link
82
+ # - :image
83
+ # - :image_type
84
+ def self.update(id, params, target=self)
85
+ request_with_key("/articles/update/#{id}", params, target)
86
+ end
87
+
88
+ # Update the article.
89
+ # params:: same as update
90
+ def update(params)
91
+ self.class.update(@id, params, self)
92
+ end
93
+
94
+ # Search articles.
95
+ # params:: see http://webservice.nifty.com/timeline/v1/articles/search.htm.
96
+ # - :timeline_key
97
+ # - :timeline_id
98
+ # - :phrase
99
+ # - :time_spec
100
+ # - :start_time
101
+ # - :end_time
102
+ # - :page
103
+ # - :hits
104
+ # - :order
105
+ # - :has_image
106
+ def self.search(params)
107
+ request("/articles/search", params, ArticlePager)
108
+ end
109
+
110
+ # Search articles by timeline id.
111
+ # timeline_id:: timeline id
112
+ def self.search_by_timeline_id(timeline_id, params={})
113
+ search(params.merge(:timeline_id => timeline_id))
114
+ end
115
+
116
+ # Search articles by phrase.
117
+ # phrase:: query words
118
+ # params:: same as search
119
+ def self.search_by_phrase(phrase, params={})
120
+ search(params.merge(:phrase => phrase))
121
+ end
122
+
123
+ # Search articles by time_spec.
124
+ # params:: same as search
125
+ def self.search_by_time_spec(time_spec, params={})
126
+ unless params.has_key?(:start_time) and params.has_key?(:end_time)
127
+ raise ArgumentError, "There is not :start_time and/or :end_time in params."
128
+ end
129
+ search(params.merge(:time_spec => time_spec))
130
+ end
131
+
132
+ # Delete an article.
133
+ # id:: article id
134
+ # timeline_key:: timeline API key
135
+ def self.delete(id, timeline_key)
136
+ request_with_key("/articles/delete/#{id}",
137
+ {:timeline_key => timeline_key},
138
+ Succeeded)
139
+ end
140
+
141
+ # Delete the article.
142
+ def delete
143
+ self.class.delete(@id, @timeline_key)
144
+ end
145
+ end
146
+ end