ntimeline 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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