io_tools 0.2.1
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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.mdown +72 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/bin/io-server +14 -0
- data/io_tools.gemspec +90 -0
- data/lib/io_tools/helpers/rss_feed.rb +11 -0
- data/lib/io_tools/helpers/xml_rpc.rb +19 -0
- data/lib/io_tools/helpers.rb +5 -0
- data/lib/io_tools/importer.rb +45 -0
- data/lib/io_tools.rb +15 -0
- data/lib/server/config.ru +3 -0
- data/lib/server/importers/posterous_api_importer.rb +74 -0
- data/lib/server/importers/posterous_feed_importer.rb +42 -0
- data/lib/server/importers/word_press_importer.rb +64 -0
- data/lib/server/public/images/bg.png +0 -0
- data/lib/server/public/javascripts/app.js +23 -0
- data/lib/server/public/stylesheets/app.css +164 -0
- data/lib/server/server.rb +36 -0
- data/lib/server/views/import.haml +18 -0
- data/lib/server/views/index.haml +71 -0
- data/spec/io_tools/helpers/rss_feed.rb +5 -0
- data/spec/io_tools/helpers/xml_rpc.rb +5 -0
- data/spec/io_tools/importer_spec.rb +62 -0
- data/spec/io_tools_spec.rb +5 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +28 -0
- metadata +177 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Christopher Burnett
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.mdown
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
## io_tools ##
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
Extracted modules from the Posterous Blog Importer. Used for conforming RSS Feeds or results from one API to another.
|
6
|
+
|
7
|
+
## Installation ##
|
8
|
+
|
9
|
+
gem install io_tools
|
10
|
+
|
11
|
+
## Usage ##
|
12
|
+
|
13
|
+
Include the Importer.
|
14
|
+
|
15
|
+
class PosterousImporter
|
16
|
+
include IoTools::Importer
|
17
|
+
end
|
18
|
+
|
19
|
+
The Importer gives you a way to structure your import code. Moving data from one API to another consists of two *basic* steps, Collecting and Conforming. The rest of the work usually ends up being specific to the API that you are dealing with. So look in the `lib/server/importers` directory for how to deal with more complicated APIs that require helper methods.
|
20
|
+
|
21
|
+
The `collect` method.
|
22
|
+
|
23
|
+
class PosterousImporter
|
24
|
+
include IoTools::Importer
|
25
|
+
|
26
|
+
collect :feed_items
|
27
|
+
|
28
|
+
def feed_items
|
29
|
+
[{:title => "Fancy Post", :body => "Is fancy."}]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
The `collect` method accepts a method name as a `symbol` or a block that will provide an `Array` of results from the API or feed. This method does not have to do all the work, all it needs to do is return an `Array`.
|
35
|
+
|
36
|
+
Hey wait, what format do the results have to be in?
|
37
|
+
|
38
|
+
It doesn't matter. This is where our friend the `conform` method comes in.
|
39
|
+
|
40
|
+
class PosterousImporter
|
41
|
+
include IoTools::Importer
|
42
|
+
|
43
|
+
collect :feed_items
|
44
|
+
|
45
|
+
conform do |incoming, conformed|
|
46
|
+
conformed.title = incoming[:title]
|
47
|
+
conformed.body = incoming[:body]
|
48
|
+
conformed
|
49
|
+
end
|
50
|
+
|
51
|
+
def feed_items
|
52
|
+
[{:title => "Fancy Post", :body => "Is fancy."}]
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
The conform method is called for every entry in the `Array` that is created by the `collect` method. This is where you turn crazy camelcase field names from weird APIs into nice clean attributes that suit your systems needs. `conform` is passed the incoming item from the `Array` produced by the `collect` method. Along with an empty `Openstruct` to hold whatever values your system needs. These in turn will populate the final `conformed_collection`.
|
58
|
+
|
59
|
+
|
60
|
+
## Note on Patches/Pull Requests
|
61
|
+
|
62
|
+
* Fork the project.
|
63
|
+
* Make your feature addition or bug fix.
|
64
|
+
* Add tests for it. This is important so I don't break it in a
|
65
|
+
future version unintentionally.
|
66
|
+
* Commit, do not mess with rakefile, version, or history.
|
67
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
68
|
+
* Send me a pull request. Bonus points for topic branches.
|
69
|
+
|
70
|
+
## Copyright
|
71
|
+
|
72
|
+
Copyright (c) 2010 Posterous Inc. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "io_tools"
|
8
|
+
gem.summary = %Q{Import framework for Blogs and Feeds}
|
9
|
+
gem.description = %Q{Extracted modules from the Posterous Blog Importer. Used for conforming RSS Feeds or results from one API to another.}
|
10
|
+
gem.email = "signalstatic@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/posterous/io_tools"
|
12
|
+
gem.authors = ["Christopher Burnett"]
|
13
|
+
gem.executables = "io-server"
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
gem.add_development_dependency "mocha"
|
16
|
+
|
17
|
+
gem.add_dependency "nokogiri", ">= 1.4.2"
|
18
|
+
gem.add_dependency "feedtools", ">= 0.2.29"
|
19
|
+
gem.add_dependency "vegas", "~> 0.1.2"
|
20
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
21
|
+
end
|
22
|
+
Jeweler::GemcutterTasks.new
|
23
|
+
rescue LoadError
|
24
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'spec/rake/spectask'
|
28
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
31
|
+
end
|
32
|
+
|
33
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
34
|
+
spec.libs << 'lib' << 'spec'
|
35
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
36
|
+
spec.rcov = true
|
37
|
+
end
|
38
|
+
|
39
|
+
task :spec => :check_dependencies
|
40
|
+
|
41
|
+
task :default => :spec
|
42
|
+
|
43
|
+
require 'rake/rdoctask'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "io_tools #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.2.1
|
data/bin/io-server
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
require 'server/server'
|
5
|
+
|
6
|
+
begin
|
7
|
+
require 'vegas'
|
8
|
+
rescue LoadError
|
9
|
+
require 'rubygems'
|
10
|
+
require 'vegas'
|
11
|
+
end
|
12
|
+
|
13
|
+
Vegas::Runner.new(IoTools::Server, 'io_server')
|
14
|
+
|
data/io_tools.gemspec
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{io_tools}
|
8
|
+
s.version = "0.2.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Christopher Burnett"]
|
12
|
+
s.date = %q{2010-08-18}
|
13
|
+
s.default_executable = %q{io-server}
|
14
|
+
s.description = %q{Extracted modules from the Posterous Blog Importer. Used for conforming RSS Feeds or results from one API to another.}
|
15
|
+
s.email = %q{signalstatic@gmail.com}
|
16
|
+
s.executables = ["io-server"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"LICENSE",
|
19
|
+
"README.mdown"
|
20
|
+
]
|
21
|
+
s.files = [
|
22
|
+
".document",
|
23
|
+
".gitignore",
|
24
|
+
"LICENSE",
|
25
|
+
"README.mdown",
|
26
|
+
"Rakefile",
|
27
|
+
"VERSION",
|
28
|
+
"bin/io-server",
|
29
|
+
"io_tools.gemspec",
|
30
|
+
"lib/io_tools.rb",
|
31
|
+
"lib/io_tools/helpers.rb",
|
32
|
+
"lib/io_tools/helpers/rss_feed.rb",
|
33
|
+
"lib/io_tools/helpers/xml_rpc.rb",
|
34
|
+
"lib/io_tools/importer.rb",
|
35
|
+
"lib/server/config.ru",
|
36
|
+
"lib/server/importers/posterous_api_importer.rb",
|
37
|
+
"lib/server/importers/posterous_feed_importer.rb",
|
38
|
+
"lib/server/importers/word_press_importer.rb",
|
39
|
+
"lib/server/public/images/bg.png",
|
40
|
+
"lib/server/public/javascripts/app.js",
|
41
|
+
"lib/server/public/stylesheets/app.css",
|
42
|
+
"lib/server/server.rb",
|
43
|
+
"lib/server/views/import.haml",
|
44
|
+
"lib/server/views/index.haml",
|
45
|
+
"spec/io_tools/helpers/rss_feed.rb",
|
46
|
+
"spec/io_tools/helpers/xml_rpc.rb",
|
47
|
+
"spec/io_tools/importer_spec.rb",
|
48
|
+
"spec/io_tools_spec.rb",
|
49
|
+
"spec/spec.opts",
|
50
|
+
"spec/spec_helper.rb"
|
51
|
+
]
|
52
|
+
s.homepage = %q{http://github.com/posterous/io_tools}
|
53
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
54
|
+
s.require_paths = ["lib"]
|
55
|
+
s.rubygems_version = %q{1.3.7}
|
56
|
+
s.summary = %q{Import framework for Blogs and Feeds}
|
57
|
+
s.test_files = [
|
58
|
+
"spec/io_tools/helpers/rss_feed.rb",
|
59
|
+
"spec/io_tools/helpers/xml_rpc.rb",
|
60
|
+
"spec/io_tools/importer_spec.rb",
|
61
|
+
"spec/io_tools_spec.rb",
|
62
|
+
"spec/spec_helper.rb"
|
63
|
+
]
|
64
|
+
|
65
|
+
if s.respond_to? :specification_version then
|
66
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
67
|
+
s.specification_version = 3
|
68
|
+
|
69
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
70
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
71
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
72
|
+
s.add_runtime_dependency(%q<nokogiri>, [">= 1.4.2"])
|
73
|
+
s.add_runtime_dependency(%q<feedtools>, [">= 0.2.29"])
|
74
|
+
s.add_runtime_dependency(%q<vegas>, ["~> 0.1.2"])
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
77
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
78
|
+
s.add_dependency(%q<nokogiri>, [">= 1.4.2"])
|
79
|
+
s.add_dependency(%q<feedtools>, [">= 0.2.29"])
|
80
|
+
s.add_dependency(%q<vegas>, ["~> 0.1.2"])
|
81
|
+
end
|
82
|
+
else
|
83
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
84
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
85
|
+
s.add_dependency(%q<nokogiri>, [">= 1.4.2"])
|
86
|
+
s.add_dependency(%q<feedtools>, [">= 0.2.29"])
|
87
|
+
s.add_dependency(%q<vegas>, ["~> 0.1.2"])
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module IoTools
|
2
|
+
module Helpers
|
3
|
+
module XmlRpc
|
4
|
+
|
5
|
+
def server
|
6
|
+
@server ||= XMLRPC::Client.new2(api_url, nil, 300)
|
7
|
+
end
|
8
|
+
|
9
|
+
def rpc method, *args
|
10
|
+
server.call("metaWeblog.#{method.to_s}", self.metaweblog_id, self.credentials[:username], self.credentials[:password], *args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def recent_posts num
|
14
|
+
rpc :getRecentPosts, num
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module IoTools
|
2
|
+
module Importer
|
3
|
+
|
4
|
+
def self.included klass
|
5
|
+
klass.class_eval do
|
6
|
+
attr_reader :params
|
7
|
+
|
8
|
+
extend ClassMethods
|
9
|
+
include InstanceMethods
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
def collect *args, &block
|
16
|
+
define_method :collection do
|
17
|
+
@collection ||= block_given? ? instance_eval(&block) : send(args.first)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def conform &block
|
22
|
+
define_method :conform do |post|
|
23
|
+
block.call(post, ItemStruct.new)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
|
31
|
+
def initialize opts={}
|
32
|
+
@params = opts
|
33
|
+
end
|
34
|
+
|
35
|
+
def conformed_collection
|
36
|
+
@conformed_collection ||= collection.collect{ |post| conform(post) }
|
37
|
+
end
|
38
|
+
|
39
|
+
def import!
|
40
|
+
conformed_collection
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/io_tools.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
%w{rubygems ostruct xmlrpc/client nokogiri open-uri feed_tools}.each { |f| require f }
|
2
|
+
|
3
|
+
|
4
|
+
require "io_tools/importer"
|
5
|
+
require "io_tools/helpers/rss_feed"
|
6
|
+
require "io_tools/helpers/xml_rpc"
|
7
|
+
|
8
|
+
module IoTools
|
9
|
+
VERSION = '0.0.1'
|
10
|
+
class ItemStruct < OpenStruct
|
11
|
+
def to_json *_
|
12
|
+
self.table.inject({}){|h,f| h[f.first] = f.last; h }.to_json
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'io_tools'
|
5
|
+
require 'xmlsimple'
|
6
|
+
|
7
|
+
class PosterousApiImporter
|
8
|
+
include IoTools::Importer
|
9
|
+
|
10
|
+
PER_PAGE_LIMIT = 50
|
11
|
+
|
12
|
+
collect :paginated_results
|
13
|
+
|
14
|
+
conform do |incoming, conformed|
|
15
|
+
conformed.title = incoming['title']
|
16
|
+
conformed.body = incoming['body']
|
17
|
+
conformed.display_date = incoming['display_date']
|
18
|
+
conformed.author = incoming['author']
|
19
|
+
conformed.comments = self.extract_comments(incoming['comment'])
|
20
|
+
conformed
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.extract_comments comments
|
24
|
+
return [] if comments.nil?
|
25
|
+
if comments.is_a? Array
|
26
|
+
comments.inject(IoTools::ItemStruct.new) do |comment,cmt|
|
27
|
+
comment.body = cmt['body']
|
28
|
+
comment.author = cmt['author']
|
29
|
+
comment.date = cmt['date']
|
30
|
+
comment
|
31
|
+
end
|
32
|
+
else
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def paginated_results
|
38
|
+
items = []
|
39
|
+
while current_items = items_for_current_page
|
40
|
+
items += current_items
|
41
|
+
self.current_page += 1
|
42
|
+
end
|
43
|
+
items
|
44
|
+
end
|
45
|
+
|
46
|
+
def url
|
47
|
+
@url ||= URI.parse('http://posterous.com/api/readposts')
|
48
|
+
end
|
49
|
+
|
50
|
+
def items_for_current_page
|
51
|
+
XmlSimple.xml_in( self.response_for_current_page, 'ForceArray' => false )['post']
|
52
|
+
end
|
53
|
+
|
54
|
+
def response_for_current_page
|
55
|
+
Net::HTTP.new(url.host, url.port).start { |http| http.request(request) }.body
|
56
|
+
end
|
57
|
+
|
58
|
+
def request
|
59
|
+
@username, @password = self.params.delete('username'), self.params.delete('password') unless @username.present?
|
60
|
+
req = Net::HTTP::Get.new(url.path)
|
61
|
+
req.basic_auth @username, @password
|
62
|
+
req.set_form_data self.params.merge('num_posts' => PER_PAGE_LIMIT, 'page' => current_page)
|
63
|
+
req
|
64
|
+
end
|
65
|
+
|
66
|
+
def current_page
|
67
|
+
@current_page ||= 1
|
68
|
+
end
|
69
|
+
|
70
|
+
def current_page=(num)
|
71
|
+
@current_page = num
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
class PosterousFeedImporter
|
3
|
+
include IoTools::Importer
|
4
|
+
include IoTools::Helpers::RssFeed
|
5
|
+
|
6
|
+
MAX_PAGES = 2
|
7
|
+
FEED_SELECTOR = 'link[type="application/rss+xml"]'
|
8
|
+
|
9
|
+
collect :paginated_feed_items
|
10
|
+
|
11
|
+
conform do |incoming, conformed|
|
12
|
+
conformed.title = incoming.title
|
13
|
+
conformed.body = incoming.description
|
14
|
+
conformed.display_date = incoming.published
|
15
|
+
conformed
|
16
|
+
end
|
17
|
+
|
18
|
+
def paginated_feed_items
|
19
|
+
items = []
|
20
|
+
1.upto(MAX_PAGES) do |num|
|
21
|
+
items += items_from_page(num)
|
22
|
+
end
|
23
|
+
items
|
24
|
+
end
|
25
|
+
|
26
|
+
def feed_url
|
27
|
+
@feed_url ||= Nokogiri::HTML(open(params[:feed_url])).css(FEED_SELECTOR).first['href']
|
28
|
+
end
|
29
|
+
|
30
|
+
def url_for_page num
|
31
|
+
puts "#{feed_url}?page=#{num}"
|
32
|
+
"#{feed_url}?page=#{num}"
|
33
|
+
end
|
34
|
+
|
35
|
+
def items_from_page num
|
36
|
+
feed_items_from(url_for_page(num))
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
# wp = PosterousFeedImporter.new(:feed_url => 'http://twoism.posterous.com')
|
42
|
+
# p wp.import!
|
@@ -0,0 +1,64 @@
|
|
1
|
+
%w{open-uri nokogiri xmlrpc/client}.each { |f| require f }
|
2
|
+
|
3
|
+
class WordPressImporter
|
4
|
+
include IoTools::Importer
|
5
|
+
include IoTools::Helpers::XmlRpc
|
6
|
+
|
7
|
+
RSD_SELECTOR = 'link[rel=EditURI]'
|
8
|
+
METAWEB_SELECTOR = 'api[name=MetaWeblog]'
|
9
|
+
MAX_POSTS_TO_REQUEST = 20
|
10
|
+
|
11
|
+
collect do
|
12
|
+
recent_posts MAX_POSTS_TO_REQUEST
|
13
|
+
end
|
14
|
+
|
15
|
+
conform do
|
16
|
+
set :title, entry['title']
|
17
|
+
set :body, entry['description']
|
18
|
+
set :display_date, entry['dateCreated'].to_time.utc
|
19
|
+
set :tags, entry['mt_keywords'].split(",")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Methods below are helpers for detecting RSD for the
|
23
|
+
# XML-RPC protocol.
|
24
|
+
def scan_for_url
|
25
|
+
rsd_doc.css( METAWEB_SELECTOR ).first['apilink']
|
26
|
+
end
|
27
|
+
|
28
|
+
def site_doc
|
29
|
+
@site_doc ||= Nokogiri::HTML(html)
|
30
|
+
end
|
31
|
+
|
32
|
+
def html
|
33
|
+
@html ||= open self.import_url
|
34
|
+
end
|
35
|
+
|
36
|
+
def rsd_url
|
37
|
+
@rsd_url ||= scan_for_rsd
|
38
|
+
end
|
39
|
+
|
40
|
+
def scan_for_rsd
|
41
|
+
site_doc.css( RSD_SELECTOR ).first['href']
|
42
|
+
end
|
43
|
+
|
44
|
+
def scan_for_id
|
45
|
+
rsd_doc.css( METAWEB_SELECTOR ).first['blogid']
|
46
|
+
end
|
47
|
+
|
48
|
+
def rsd_doc
|
49
|
+
@rsd_doc ||= Nokogiri::HTML(rsd_html)
|
50
|
+
end
|
51
|
+
|
52
|
+
def rsd_html
|
53
|
+
@rsd_html ||= open(rsd_url)
|
54
|
+
end
|
55
|
+
|
56
|
+
def metaweblog_id
|
57
|
+
@metaweblog_id ||= scan_for_id
|
58
|
+
end
|
59
|
+
|
60
|
+
def api_url
|
61
|
+
@api_url ||= scan_for_url
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
$(function(){
|
2
|
+
|
3
|
+
var service = null;
|
4
|
+
|
5
|
+
$('#service').change(function(){
|
6
|
+
service = $(this).val();
|
7
|
+
if (service != '') {
|
8
|
+
$('.login_info').slideUp('medium',function(){
|
9
|
+
$('#'+service).slideDown('medium');
|
10
|
+
});
|
11
|
+
}
|
12
|
+
});
|
13
|
+
$('.login_info').submit(function(e){
|
14
|
+
e.preventDefault();
|
15
|
+
$('#loading').show();
|
16
|
+
$('#posts').html("");
|
17
|
+
var params = $('#'+service).serialize();
|
18
|
+
$.post('/import', params ,function(data){
|
19
|
+
$('#posts').html(data);
|
20
|
+
$('#loading').hide();
|
21
|
+
});
|
22
|
+
});
|
23
|
+
});
|
@@ -0,0 +1,164 @@
|
|
1
|
+
body {font-size: 16px; line-height: 1.25em; margin: 0; padding: 0; }
|
2
|
+
|
3
|
+
html, body {background: #eee url(/images/bg.png); font-family: "helvetica neue", arial, sans-serif}
|
4
|
+
|
5
|
+
h1 {margin: 0; font-size: 1.5em; line-height: 0.833em; margin-bottom: 0.833em}
|
6
|
+
h2 {margin: 0; font-size: 1.375em; line-height: 0.909em; margin-bottom: 0.909em}
|
7
|
+
h3 {margin: 0; font-size: 1.25em; line-height: 1em; margin-bottom: 1em}
|
8
|
+
h4 {margin: 0; font-size: 1.125em; line-height: 1.111em; margin-bottom: 1.111em}
|
9
|
+
|
10
|
+
p, ul, blockquote, pre, td, th, label {margin: 0; font-size: 1em; line-height: 1.25em; margin-bottom: 1.25em}
|
11
|
+
|
12
|
+
.panel {border-radius: 8px; -moz-border-radius: 8px; -webkit-border-radius: 8px; -khtml-border-radius: 8px; behavior: url(stylesheets/border-radius.htc); box-shadow: 0 0 2px #eeeeee; -moz-box-shadow: 0 0 2px #eeeeee; -webkit-box-shadow: 0 0 2px #eeeeee; -khtml-box-shadow: 0 0 2px #eeeeee; border: 1px solid #ccc; background-color: #fff; margin-bottom: 1.25em}
|
13
|
+
.panel .panel_title {-moz-border-radius-topleft: 8px; border-top-left-radius: 8px; -webkit-border-top-left-radius: 8px; -khtml-border-top-left-radius: 8px; -moz-border-radius-topright: 8px; border-top-right-radius: 8px; -webkit-border-top-right-radius: 8px; -khtml-border-top-right-radius: 8px; background: white url(/images/panel_title_bg.gif) 0 bottom repeat-x; line-height: 47px; font-size: 1.125em; color: #4b4f5d; font-weight: bold; padding: 0 24px; border-bottom: 1px solid #ccc; box-shadow: 0 0 2px #eeeeee; -moz-box-shadow: 0 0 2px #eeeeee; -webkit-box-shadow: 0 0 2px #eeeeee; -khtml-box-shadow: 0 0 2px #eeeeee; text-shadow: #fff 0px 1px 0px;}
|
14
|
+
.panel .panel_title .octocat {vertical-align: middle; margin-right: 5px}
|
15
|
+
.panel .panel_title a.add-new {float: right; font-size: 0.667em; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -khtml-border-radius: 3px; behavior: url(stylesheets/border-radius.htc); border: 1px solid #ccc; line-height: 1.667em; padding: 5px 7px; margin: 8px 0 0 5px; background: #d4d4d4 url(/images/gray-gradient-pagination-bg.png) 0 0 repeat-x; color: #4B4F5D}
|
16
|
+
.panel .panel_title a.add-new:hover {box-shadow: 0 1px 3px #666666; -moz-box-shadow: 0 1px 3px #666666; -webkit-box-shadow: 0 1px 3px #666666; -khtml-box-shadow: 0 1px 3px #666666; border-color: #ccc; background-image: none; background-color: #fff}
|
17
|
+
.panel .panel_content {padding: 1em}
|
18
|
+
|
19
|
+
#container {
|
20
|
+
width:450px;
|
21
|
+
margin:auto;
|
22
|
+
border-bottom:1px #ccc solid;
|
23
|
+
clear:right;
|
24
|
+
}
|
25
|
+
|
26
|
+
|
27
|
+
#header {
|
28
|
+
border-bottom:1px solid #ccc;
|
29
|
+
height:25px;
|
30
|
+
padding:1em;
|
31
|
+
}
|
32
|
+
|
33
|
+
#header h2{
|
34
|
+
text-shadow: #fff 0px 1px 0px;
|
35
|
+
color:#4b4f5d;
|
36
|
+
}
|
37
|
+
|
38
|
+
select#service{
|
39
|
+
|
40
|
+
}
|
41
|
+
|
42
|
+
#left_nav {
|
43
|
+
padding:1em;
|
44
|
+
width:200px;
|
45
|
+
float:left;
|
46
|
+
}
|
47
|
+
|
48
|
+
#left_nav ul {
|
49
|
+
list-style:none;
|
50
|
+
padding:0;
|
51
|
+
}
|
52
|
+
#main {
|
53
|
+
padding:1em;
|
54
|
+
float:left;
|
55
|
+
|
56
|
+
}
|
57
|
+
|
58
|
+
.login_info{
|
59
|
+
|
60
|
+
float:left;
|
61
|
+
}
|
62
|
+
|
63
|
+
.login_info p{
|
64
|
+
height:30px;
|
65
|
+
width:100%;
|
66
|
+
float:left;
|
67
|
+
padding:0px 0px 3px 0px;
|
68
|
+
}
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
.login_info label{
|
73
|
+
position:relative;
|
74
|
+
font-weight:bold;
|
75
|
+
float:left;
|
76
|
+
color:#4B4F5D;
|
77
|
+
text-shadow:0 1px 0 #FFFFFF;
|
78
|
+
clear:left;
|
79
|
+
font-size:14px;
|
80
|
+
letter-spacing:.02em;
|
81
|
+
bottom:-8px;
|
82
|
+
}
|
83
|
+
|
84
|
+
.login_info input{
|
85
|
+
border:1px solid #DEDEDE;
|
86
|
+
float:right;
|
87
|
+
background-color:#F6F6F6;
|
88
|
+
padding:10px;
|
89
|
+
|
90
|
+
-webkit-border-top-left-radius: 4px;
|
91
|
+
-webkit-border-top-right-radius: 4px;
|
92
|
+
-webkit-border-bottom-right-radius: 4px;
|
93
|
+
-webkit-border-bottom-left-radius: 4px;
|
94
|
+
-moz-border-radius-topleft: 4px;
|
95
|
+
-moz-border-radius-topright: 4px;
|
96
|
+
-moz-border-radius-bottomright: 4px;
|
97
|
+
-moz-border-radius-bottomleft: 4px;
|
98
|
+
border-top-left-radius: 4px;
|
99
|
+
border-top-right-radius: 4px;
|
100
|
+
border-bottom-right-radius: 4px;
|
101
|
+
border-bottom-left-radius: 4px;
|
102
|
+
|
103
|
+
}
|
104
|
+
|
105
|
+
#chooser{margin:auto;}
|
106
|
+
|
107
|
+
input.text_field{
|
108
|
+
width:315px;
|
109
|
+
}
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
.login_info p.last{
|
114
|
+
padding-bottom:0px;
|
115
|
+
margin:0px;
|
116
|
+
|
117
|
+
}
|
118
|
+
|
119
|
+
.login_info p input[type="submit"]{
|
120
|
+
background-color:#F6F6F6;
|
121
|
+
text-shadow:0 1px 0 #DEDEDE;
|
122
|
+
font-weight:bold;
|
123
|
+
width:75px;
|
124
|
+
height:30px;
|
125
|
+
padding:0px 0px 2px 0px;
|
126
|
+
}
|
127
|
+
|
128
|
+
.login_info p input[type="submit"]:hover{
|
129
|
+
background-color:#DEDEDE;
|
130
|
+
}
|
131
|
+
|
132
|
+
.post{
|
133
|
+
background:none repeat scroll 0 0 #FFFFFF;
|
134
|
+
border:1px solid #CCCCCC;
|
135
|
+
margin-bottom:1em;
|
136
|
+
padding:1em;
|
137
|
+
}
|
138
|
+
|
139
|
+
.post_title{
|
140
|
+
background:none repeat scroll 0 0 #EEEEEE;
|
141
|
+
margin-bottom:10px;
|
142
|
+
padding:0.5em;
|
143
|
+
}
|
144
|
+
|
145
|
+
.post_body{
|
146
|
+
background:none repeat scroll 0 0 #EEEEEE;
|
147
|
+
margin-bottom:10px;
|
148
|
+
width:386px;
|
149
|
+
overflow:auto;
|
150
|
+
padding:0.5em;
|
151
|
+
}
|
152
|
+
|
153
|
+
.post_tags{
|
154
|
+
background:none repeat scroll 0 0 #EEEEEE;
|
155
|
+
margin-bottom:10px;
|
156
|
+
padding:0.5em;
|
157
|
+
}
|
158
|
+
|
159
|
+
textarea{
|
160
|
+
border:1px solid #CCCCCC;
|
161
|
+
margin:10px 0;
|
162
|
+
width:430px;
|
163
|
+
height:200px;
|
164
|
+
}
|
@@ -0,0 +1,36 @@
|
|
1
|
+
%w{rubygems sinatra haml}.each { |f| require f }
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
4
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '../..', 'lib'))
|
5
|
+
|
6
|
+
require 'io_tools'
|
7
|
+
dir = File.expand_path(File.dirname(__FILE__))
|
8
|
+
|
9
|
+
require dir+'/importers/posterous_feed_importer'
|
10
|
+
require dir+'/importers/posterous_api_importer'
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
module IoTools
|
15
|
+
|
16
|
+
|
17
|
+
class Server < Sinatra::Base
|
18
|
+
dir = File.dirname(File.expand_path(__FILE__))
|
19
|
+
|
20
|
+
set :views, "#{dir}/views"
|
21
|
+
set :public, "#{dir}/public"
|
22
|
+
|
23
|
+
get "/" do
|
24
|
+
haml :index
|
25
|
+
end
|
26
|
+
|
27
|
+
post '/import' do
|
28
|
+
klass = params.delete('service').camelize.constantize
|
29
|
+
@import = klass.new(params)
|
30
|
+
@posts = @import.import!
|
31
|
+
haml :import
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
%h4 Exported JSON
|
2
|
+
%textarea{:id => "xml_export"}
|
3
|
+
= @posts.to_json
|
4
|
+
|
5
|
+
%h4 Posts
|
6
|
+
- @posts.each do |post|
|
7
|
+
.post
|
8
|
+
.post_title
|
9
|
+
%h4 Title
|
10
|
+
%p
|
11
|
+
= "#{post.title} - #{post.display_date}"
|
12
|
+
.post_body
|
13
|
+
%h4 Body
|
14
|
+
= post.body
|
15
|
+
.post_tags
|
16
|
+
%h4 Tags
|
17
|
+
%p
|
18
|
+
= post.tags.join(",") unless post.tags.nil?
|
@@ -0,0 +1,71 @@
|
|
1
|
+
!!!
|
2
|
+
%html
|
3
|
+
%head
|
4
|
+
%title
|
5
|
+
Importer
|
6
|
+
%script{:src => 'http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js', :type => 'text/javascript'}
|
7
|
+
%script{:src => '/javascripts/app.js', :type => 'text/javascript'}
|
8
|
+
%link{:type => 'text/css', :rel=>"stylesheet", :href => '/stylesheets/app.css' }
|
9
|
+
|
10
|
+
%body
|
11
|
+
#container
|
12
|
+
#header
|
13
|
+
%h2 Export Tools
|
14
|
+
#main
|
15
|
+
|
16
|
+
#chooser
|
17
|
+
%p
|
18
|
+
%select{:id => 'service'}
|
19
|
+
%option{ :value => '' }
|
20
|
+
Choose Blog Service:
|
21
|
+
%option{ :value => 'posterous_api_importer' }
|
22
|
+
Posterous API
|
23
|
+
%option{ :value => 'posterous_feed_importer' }
|
24
|
+
Posterous Feed
|
25
|
+
|
26
|
+
%form.login_info{:style => 'display:none', :id => 'posterous_api_importer', :method => "POST"}
|
27
|
+
%p
|
28
|
+
%label
|
29
|
+
Email:
|
30
|
+
%input{:name => "username", :type => 'text', :value => '',:class=>"text_field"}
|
31
|
+
%br{:clear => "all"}
|
32
|
+
%p
|
33
|
+
%label
|
34
|
+
Password:
|
35
|
+
%input{:name => "password", :type => 'password', :value => '',:class=>"text_field"}
|
36
|
+
%p
|
37
|
+
%label
|
38
|
+
Hostname:
|
39
|
+
%input{:name => "hostname", :type => 'text', :value => '',:class=>"text_field"}
|
40
|
+
%input{:name => "service", :type => 'hidden', :value => 'posterous_api_importer',:class=>"text_field"}
|
41
|
+
|
42
|
+
|
43
|
+
%p
|
44
|
+
%input{:id => "submit_btn",:value => 'Export', :type => "submit"}
|
45
|
+
|
46
|
+
%br{:clear => "all"}
|
47
|
+
|
48
|
+
%form.login_info{:style => 'display:none', :id => 'posterous_feed_importer', :method => "POST"}
|
49
|
+
%p
|
50
|
+
%label
|
51
|
+
Site URL:
|
52
|
+
%input{:name => "feed_url", :type => 'text', :value => '',:class=>"text_field"}
|
53
|
+
%input{:name => "service", :type => 'hidden', :value => 'posterous_feed_importer',:class=>"text_field"}
|
54
|
+
|
55
|
+
|
56
|
+
%p
|
57
|
+
%input{:id => "submit_btn",:value => 'Export', :type => "submit"}
|
58
|
+
|
59
|
+
%br{:clear => "all"}
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
#loading{:style => 'display:none'}
|
64
|
+
%p Loading...
|
65
|
+
|
66
|
+
|
67
|
+
%br{:clear => "all"}
|
68
|
+
#posts
|
69
|
+
|
70
|
+
%br{:clear => "all"}
|
71
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe IoTools::Importer do
|
4
|
+
describe "#new" do
|
5
|
+
|
6
|
+
describe "with an import url" do
|
7
|
+
before(:each) do
|
8
|
+
@import = Import.new(:import_url => 'http://sweetness.com')
|
9
|
+
end
|
10
|
+
it "should set the :import_url" do
|
11
|
+
@import.params[:import_url].should == 'http://sweetness.com'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#conform" do
|
17
|
+
before(:each) do
|
18
|
+
@import = Import.new(:import_url => 'http://sweetness.com')
|
19
|
+
@hash = ENTRY_HASH
|
20
|
+
@conformed = @import.conform(@hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "conform hash keys" do
|
24
|
+
ENTRY_HASH.each do |k,v|
|
25
|
+
it "should set :#{k} to #{v}" do
|
26
|
+
@conformed.send(k).should == v
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#collection" do
|
33
|
+
before(:each) do
|
34
|
+
@import = Import.new(:import_url => 'http://sweetness.com')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should be an Array" do
|
38
|
+
@import.collection.should be_an Array
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should contain the hashes" do
|
42
|
+
@import.collection.each{|e| e.should be_a Hash }
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#conformed_collection" do
|
48
|
+
before(:each) do
|
49
|
+
@import = Import.new(:import_url => 'http://sweetness.com')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should be an Array" do
|
53
|
+
@import.conformed_collection.should be_an Array
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should contain the conformed structs" do
|
57
|
+
@import.conformed_collection.each{|e| e.should be_a IoTools::ItemStruct }
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
|
4
|
+
require 'io_tools'
|
5
|
+
require 'spec'
|
6
|
+
require 'spec/autorun'
|
7
|
+
require 'mocha'
|
8
|
+
|
9
|
+
Spec::Runner.configure do |config|
|
10
|
+
config.mock_with :mocha
|
11
|
+
end
|
12
|
+
|
13
|
+
ENTRY_HASH = {:title => "Sweet", :body => "An awesome post!"}
|
14
|
+
|
15
|
+
class Import
|
16
|
+
include IoTools::Importer
|
17
|
+
|
18
|
+
conform do |incoming,conformed|
|
19
|
+
conformed.title = incoming[:title]
|
20
|
+
conformed.body = incoming[:body]
|
21
|
+
conformed
|
22
|
+
end
|
23
|
+
|
24
|
+
collect do
|
25
|
+
[ENTRY_HASH,ENTRY_HASH]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: io_tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 21
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 1
|
10
|
+
version: 0.2.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Christopher Burnett
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-08-18 00:00:00 -07:00
|
19
|
+
default_executable: io-server
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: rspec
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 1
|
32
|
+
- 2
|
33
|
+
- 9
|
34
|
+
version: 1.2.9
|
35
|
+
type: :development
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: mocha
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 3
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
type: :development
|
50
|
+
version_requirements: *id002
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: nokogiri
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 1
|
62
|
+
- 4
|
63
|
+
- 2
|
64
|
+
version: 1.4.2
|
65
|
+
type: :runtime
|
66
|
+
version_requirements: *id003
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: feedtools
|
69
|
+
prerelease: false
|
70
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
71
|
+
none: false
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
hash: 45
|
76
|
+
segments:
|
77
|
+
- 0
|
78
|
+
- 2
|
79
|
+
- 29
|
80
|
+
version: 0.2.29
|
81
|
+
type: :runtime
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: vegas
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 31
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
- 1
|
95
|
+
- 2
|
96
|
+
version: 0.1.2
|
97
|
+
type: :runtime
|
98
|
+
version_requirements: *id005
|
99
|
+
description: Extracted modules from the Posterous Blog Importer. Used for conforming RSS Feeds or results from one API to another.
|
100
|
+
email: signalstatic@gmail.com
|
101
|
+
executables:
|
102
|
+
- io-server
|
103
|
+
extensions: []
|
104
|
+
|
105
|
+
extra_rdoc_files:
|
106
|
+
- LICENSE
|
107
|
+
- README.mdown
|
108
|
+
files:
|
109
|
+
- .document
|
110
|
+
- .gitignore
|
111
|
+
- LICENSE
|
112
|
+
- README.mdown
|
113
|
+
- Rakefile
|
114
|
+
- VERSION
|
115
|
+
- bin/io-server
|
116
|
+
- io_tools.gemspec
|
117
|
+
- lib/io_tools.rb
|
118
|
+
- lib/io_tools/helpers.rb
|
119
|
+
- lib/io_tools/helpers/rss_feed.rb
|
120
|
+
- lib/io_tools/helpers/xml_rpc.rb
|
121
|
+
- lib/io_tools/importer.rb
|
122
|
+
- lib/server/config.ru
|
123
|
+
- lib/server/importers/posterous_api_importer.rb
|
124
|
+
- lib/server/importers/posterous_feed_importer.rb
|
125
|
+
- lib/server/importers/word_press_importer.rb
|
126
|
+
- lib/server/public/images/bg.png
|
127
|
+
- lib/server/public/javascripts/app.js
|
128
|
+
- lib/server/public/stylesheets/app.css
|
129
|
+
- lib/server/server.rb
|
130
|
+
- lib/server/views/import.haml
|
131
|
+
- lib/server/views/index.haml
|
132
|
+
- spec/io_tools/helpers/rss_feed.rb
|
133
|
+
- spec/io_tools/helpers/xml_rpc.rb
|
134
|
+
- spec/io_tools/importer_spec.rb
|
135
|
+
- spec/io_tools_spec.rb
|
136
|
+
- spec/spec.opts
|
137
|
+
- spec/spec_helper.rb
|
138
|
+
has_rdoc: true
|
139
|
+
homepage: http://github.com/posterous/io_tools
|
140
|
+
licenses: []
|
141
|
+
|
142
|
+
post_install_message:
|
143
|
+
rdoc_options:
|
144
|
+
- --charset=UTF-8
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
hash: 3
|
153
|
+
segments:
|
154
|
+
- 0
|
155
|
+
version: "0"
|
156
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
157
|
+
none: false
|
158
|
+
requirements:
|
159
|
+
- - ">="
|
160
|
+
- !ruby/object:Gem::Version
|
161
|
+
hash: 3
|
162
|
+
segments:
|
163
|
+
- 0
|
164
|
+
version: "0"
|
165
|
+
requirements: []
|
166
|
+
|
167
|
+
rubyforge_project:
|
168
|
+
rubygems_version: 1.3.7
|
169
|
+
signing_key:
|
170
|
+
specification_version: 3
|
171
|
+
summary: Import framework for Blogs and Feeds
|
172
|
+
test_files:
|
173
|
+
- spec/io_tools/helpers/rss_feed.rb
|
174
|
+
- spec/io_tools/helpers/xml_rpc.rb
|
175
|
+
- spec/io_tools/importer_spec.rb
|
176
|
+
- spec/io_tools_spec.rb
|
177
|
+
- spec/spec_helper.rb
|