yapra 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,11 @@
1
+ == 0.1.3
2
+
3
+ * 1 bug fix:
4
+
5
+ * 2 majar enhancement:
6
+ * Publish::Mail plugin is added.
7
+ * Feed::Custom supports url list.
8
+
1
9
  == 0.1.2
2
10
 
3
11
  * 1 bug fix:
data/LICENCE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008 fraction.jp. Some rights reserved.
1
+ Copyright (c) 2008 Yuanying Ohtsuka
2
2
 
3
3
  Original from 2008-06-12 http://pragger.ikejisoft.com/
4
4
 
data/README.mdown ADDED
@@ -0,0 +1,70 @@
1
+ yapra
2
+ ====================================
3
+ - http://yapra.rubyforge.org/
4
+ - http://github.com/yuanying/yapra/tree/master
5
+
6
+ DESCRIPTION:
7
+ ------------------------------------
8
+ Yet Another Pragger(http://pragger.ikejisoft.com/) implementation.
9
+
10
+ FEATURES/PROBLEMS:
11
+ ------------------------------------
12
+ - 99% compatible of Pragger.
13
+ - Class-based plugin support.
14
+ - Loadpass based plugin loading strategy. (also support pragger's plugin in advance mode.)
15
+ - Support Python habu like config file.
16
+
17
+ SYNOPSIS:
18
+ ------------------------------------
19
+
20
+ ### Use at command
21
+
22
+ $ yapra -c config_file.yml
23
+
24
+ ### Use in your application
25
+
26
+ require 'yapra/runtime'
27
+ require 'yapra/config'
28
+
29
+ config = YAML.load(config_file)
30
+ config = Yapra::Config.new(config)
31
+
32
+ Yapra::Runtime.logger = Logger.new(STDOUT)
33
+
34
+ yapra = Yapra::Runtime.new(config.env)
35
+ yapra.execute(config.pipeline_commands)
36
+
37
+ ### REQUIREMENTS:
38
+
39
+ - mechanize (>= 0.7.6)
40
+
41
+ INSTALL:
42
+ ------------------------------------
43
+
44
+ sudo gem install yapra
45
+
46
+ LICENSE:
47
+ ------------------------------------
48
+
49
+ (The MIT License)
50
+
51
+ Copyright (c) 2008 Yuanying Ohtsuka
52
+
53
+ Permission is hereby granted, free of charge, to any person obtaining
54
+ a copy of this software and associated documentation files (the
55
+ 'Software'), to deal in the Software without restriction, including
56
+ without limitation the rights to use, copy, modify, merge, publish,
57
+ distribute, sublicense, and/or sell copies of the Software, and to
58
+ permit persons to whom the Software is furnished to do so, subject to
59
+ the following conditions:
60
+
61
+ The above copyright notice and this permission notice shall be
62
+ included in all copies or substantial portions of the Software.
63
+
64
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
65
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
66
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
67
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
68
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
69
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
70
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -1,13 +1,119 @@
1
- require 'config/requirements'
2
- require 'config/hoe' # setup Hoe + all gem configuration
3
-
4
- Dir['tasks/**/*.rake'].each { |rake| load rake }
5
-
6
- ##############################################################################
7
- # SVN
8
- ##############################################################################
9
-
10
- desc "Add new files to subversion"
11
- task :svn_add do
12
- system "svn status | grep '^\?' | sed -e 's/? *//' | sed -e 's/ /\ /g' | xargs svn add"
13
- end
1
+ $:.unshift('lib')
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/clean'
5
+ require 'rake/testtask'
6
+ require 'rake/packagetask'
7
+ require 'rake/gempackagetask'
8
+ require 'rake/rdoctask'
9
+ require 'rake/contrib/rubyforgepublisher'
10
+ require 'rake/contrib/sshpublisher'
11
+ require 'fileutils'
12
+ require 'yapra/version'
13
+ include FileUtils
14
+ NAME = "yapra"
15
+ AUTHOR = "yuanying"
16
+ EMAIL = "yuanying at fraction dot jp"
17
+ DESCRIPTION = "Yet another pragger implementation."
18
+ RUBYFORGE_PROJECT = "yapra"
19
+ HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
20
+ BIN_FILES = %w( yapra )
21
+ VERS = Yapra::VERSION::STRING
22
+
23
+ REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
24
+ CLEAN.include ['**/.*.sw?', '*.gem', '.config' ,'pkg']
25
+ RDOC_OPTS = [
26
+ '--title', "#{NAME} documentation",
27
+ "--charset", "utf-8",
28
+ "--opname", "index.html",
29
+ "--line-numbers",
30
+ "--main", "README.mdown",
31
+ "--inline-source",
32
+ ]
33
+
34
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
35
+
36
+ task :default => [:spec]
37
+ task :package => [:clean]
38
+
39
+ spec = Gem::Specification.new do |s|
40
+ s.name = NAME
41
+ s.version = VERS
42
+ s.platform = Gem::Platform::RUBY
43
+ s.has_rdoc = true
44
+ s.extra_rdoc_files = ["README.mdown", "ChangeLog"]
45
+ s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
46
+ s.summary = DESCRIPTION
47
+ s.description = DESCRIPTION
48
+ s.author = AUTHOR
49
+ s.email = EMAIL
50
+ s.homepage = HOMEPATH
51
+ s.executables = BIN_FILES
52
+ s.rubyforge_project = RUBYFORGE_PROJECT
53
+ s.bindir = "bin"
54
+ s.require_paths << "lib-plugins"
55
+ s.autorequire = ""
56
+ s.test_files = Dir["test/test_*.rb"]
57
+
58
+ s.add_dependency('mechanize', '>=0.7.6')
59
+ #s.required_ruby_version = '>= 1.8.2'
60
+
61
+ s.files = %w(README.mdown ChangeLog Rakefile LICENCE) +
62
+ Dir.glob("{bin,doc,fixtures,legacy_plugins,lib,lib-plugins,plugins,spec,tasks,website,script}/**/*") +
63
+ # Dir.glob("ext/**/*.{h,c,rb}") +
64
+ # Dir.glob("examples/**/*.rb") +
65
+ # Dir.glob("tools/*.rb")
66
+
67
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
68
+ end
69
+
70
+ Rake::GemPackageTask.new(spec) do |p|
71
+ p.need_tar = true
72
+ p.gem_spec = spec
73
+ end
74
+
75
+ task :install do
76
+ name = "#{NAME}-#{VERS}.gem"
77
+ sh %{rake package}
78
+ sh %{sudo gem install pkg/#{name}}
79
+ end
80
+
81
+ task :uninstall => [:clean] do
82
+ sh %{sudo gem uninstall #{NAME}}
83
+ end
84
+
85
+
86
+ Rake::RDocTask.new do |rdoc|
87
+ rdoc.rdoc_dir = 'html'
88
+ rdoc.options += RDOC_OPTS
89
+ rdoc.template = "resh"
90
+ #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
91
+ if ENV['DOC_FILES']
92
+ rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
93
+ else
94
+ rdoc.rdoc_files.include('README', 'ChangeLog')
95
+ rdoc.rdoc_files.include('lib/**/*.rb')
96
+ rdoc.rdoc_files.include('ext/**/*.c')
97
+ end
98
+ end
99
+
100
+ desc "Publish to RubyForge"
101
+ task :rubyforge => [:rdoc, :package] do
102
+ require 'rubyforge'
103
+ Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'yuanying').upload
104
+ end
105
+
106
+ desc 'Package and upload the release to gemcutter.'
107
+ task :release => [:clean, :package] do |t|
108
+ v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
109
+ abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
110
+ pkg = "pkg/#{NAME}-#{VERS}"
111
+
112
+ files = [
113
+ "#{pkg}.tgz",
114
+ "#{pkg}.gem"
115
+ ].compact
116
+
117
+ puts "Releasing #{NAME} v. #{VERS}"
118
+ sh %{gem push #{pkg}.gem}
119
+ end
data/bin/yapra CHANGED
@@ -23,11 +23,13 @@ require 'yapra/runtime'
23
23
  require 'yapra/config'
24
24
  require 'yapra/legacy_plugin/registry_factory'
25
25
 
26
- Version = Yapra::VERSION::STRING
27
26
  mode = 'compatible'
28
27
  config_files = []#"config.yaml"
29
28
  loglebel = nil
29
+
30
30
  opt = OptionParser.new
31
+ opt.version = Yapra::VERSION::STRING
32
+ opt.release = nil
31
33
  opt.on("-c", "--configfile CONFIGFILE") {|v| config_files << v }
32
34
  opt.on("-d", "--configfile-directory CONFIGFILE_DIRECTORY") { |v|
33
35
  Dir.glob(File.join(v, '**/*.yml')).each do |file|
@@ -1,31 +1,14 @@
1
1
  require 'yapra'
2
+ require 'yapra/pipeline_base'
2
3
  require 'yapra/runtime'
3
4
  require 'yapra/inflector'
4
5
  require 'yapra/legacy_plugin/base'
5
6
 
6
- class Yapra::Pipeline
7
- attr_reader :yapra, :context
8
- attr_writer :logger
7
+ class Yapra::Pipeline < Yapra::PipelineBase
9
8
  attr_accessor :legacy_plugin_registry
10
9
 
11
10
  UPPER_CASE = /[A-Z]/
12
11
 
13
- def initialize pipeline_name, yapra=Yapra::Runtime.new
14
- @logger = nil
15
- @yapra = yapra
16
- @context = { 'pipeline_name' => pipeline_name }
17
-
18
- @module_name_prefix = construct_module_name_prefix yapra.env
19
- end
20
-
21
- def name
22
- self.context[ 'pipeline_name' ]
23
- end
24
-
25
- def logger
26
- return @logger || Yapra::Runtime.logger
27
- end
28
-
29
12
  # start pipeline from commands.
30
13
  #
31
14
  # example:
@@ -87,20 +70,11 @@ class Yapra::Pipeline
87
70
 
88
71
  def run_class_based_plugin command, data
89
72
  self.logger.debug("evaluate plugin as class based")
90
- load_error_stack = []
91
- plugin_class = nil
92
- @module_name_prefix.each do |prefix|
93
- yapra_module_name = "#{prefix}#{command['module']}"
94
- begin
95
- plugin_class = Yapra.load_class_constant(yapra_module_name)
96
- break if plugin_class
97
- rescue LoadError, NameError => ex
98
- load_error_stack << ex
99
- end
100
- end
101
- raise_load_error(load_error_stack, command) unless plugin_class
73
+ plugin = load(command['module'])
74
+
75
+ # yml pipeline specific.
76
+ plugin.plugin_config = command['config'] if plugin.respond_to?('plugin_config=')
102
77
 
103
- plugin = initialize_plugin(plugin_class, command)
104
78
  @plugins << plugin
105
79
  data = plugin.run(data)
106
80
  return data
@@ -116,24 +90,4 @@ class Yapra::Pipeline
116
90
  load_error.set_backtrace(backtrace)
117
91
  raise load_error
118
92
  end
119
-
120
- def initialize_plugin plugin_class, command
121
- plugin = plugin_class.new
122
- plugin.yapra = yapra if plugin.respond_to?('yapra=')
123
- plugin.pipeline = self if plugin.respond_to?('pipeline=')
124
- plugin.plugin_config = command['config'] if plugin.respond_to?('plugin_config=')
125
- plugin
126
- end
127
-
128
- def construct_module_name_prefix env
129
- module_name_prefix = [ 'Yapra::Plugin::', '' ]
130
- if env['module_name_prefix']
131
- if env['module_name_prefix'].kind_of?(Array)
132
- module_name_prefix = env['module_name_prefix']
133
- else
134
- module_name_prefix = [ env['module_name_prefix'] ]
135
- end
136
- end
137
- module_name_prefix
138
- end
139
93
  end
@@ -0,0 +1,64 @@
1
+ require 'yapra'
2
+ require 'yapra/inflector'
3
+ require 'yapra/legacy_plugin/base'
4
+
5
+ class Yapra::PipelineBase
6
+ attr_reader :yapra, :context
7
+ attr_writer :logger
8
+
9
+ def initialize pipeline_name, yapra=Yapra::Runtime.new
10
+ @logger = nil
11
+ @yapra = yapra
12
+ @context = { 'pipeline_name' => pipeline_name }
13
+
14
+ @module_name_prefix = construct_module_name_prefix yapra.env
15
+ end
16
+
17
+ def name
18
+ self.context[ 'pipeline_name' ]
19
+ end
20
+
21
+ def logger
22
+ return @logger || Yapra::Runtime.logger
23
+ end
24
+
25
+ def load plugin_name
26
+ load_error_stack = []
27
+ plugin_class = nil
28
+ @module_name_prefix.each do |prefix|
29
+ yapra_module_name = "#{prefix}#{plugin_name}"
30
+ begin
31
+ plugin_class = Yapra.load_class_constant(yapra_module_name)
32
+ break if plugin_class
33
+ rescue LoadError, NameError => ex
34
+ load_error_stack << ex
35
+ end
36
+ end
37
+ raise_load_error(load_error_stack, command) unless plugin_class
38
+
39
+ plugin = initialize_plugin( plugin_class )
40
+
41
+ plugin
42
+ end
43
+
44
+ protected
45
+ def initialize_plugin plugin_class
46
+ plugin = plugin_class.new
47
+ plugin.yapra = yapra if plugin.respond_to?('yapra=')
48
+ plugin.pipeline = self if plugin.respond_to?('pipeline=')
49
+
50
+ plugin
51
+ end
52
+
53
+ def construct_module_name_prefix env
54
+ module_name_prefix = [ 'Yapra::Plugin::', '' ]
55
+ if env['module_name_prefix']
56
+ if env['module_name_prefix'].kind_of?(Array)
57
+ module_name_prefix = env['module_name_prefix']
58
+ else
59
+ module_name_prefix = [ env['module_name_prefix'] ]
60
+ end
61
+ end
62
+ module_name_prefix
63
+ end
64
+ end
@@ -8,7 +8,7 @@ class Yapra::Plugin::MechanizeBase < Yapra::Plugin::Base
8
8
  pipeline.context['mechanize_agent']
9
9
  end
10
10
 
11
- def extract_attribute_from element, item
11
+ def extract_attribute_from element, item, binding=nil
12
12
  if plugin_config['extract_xpath']
13
13
  plugin_config['extract_xpath'].each do |k, v|
14
14
  value = nil
@@ -0,0 +1,7 @@
1
+ require 'yapra'
2
+ require 'yapra/inflector'
3
+ require 'yapra/legacy_plugin/base'
4
+
5
+ class Yapra::RbPipeline < Yapra::PipelineBase
6
+
7
+ end
data/lib/yapra/version.rb CHANGED
@@ -2,7 +2,7 @@ module Yapra
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 0
4
4
  MINOR = 1
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
data/lib/yapra.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2008 fraction.jp. Yuanying, Some rights reserved.
2
+ # Copyright (c) 2008 Yuanying Ohtsuka
3
3
  # Original from 2008-06-12 http://pragger.ikejisoft.com/
4
4
  #
5
5
  # Permission is hereby granted, free of charge, to any person obtaining
@@ -20,24 +20,37 @@ module Yapra::Plugin::Feed
20
20
  # content_encoded: '<div><%= title %></div>'
21
21
  class Custom < Yapra::Plugin::MechanizeBase
22
22
  def run(data)
23
- page = agent.get(config['url'])
24
- root = page.root
25
-
23
+ urls =
24
+ if config['url'].kind_of?(Array)
25
+ config['url']
26
+ else
27
+ [ config['url'] ]
28
+ end
26
29
  xconfig = config['extract_xpath']
30
+ wait = config['wait'] || 1
31
+ capture = xconfig['capture']
32
+ split = xconfig['split']
27
33
 
28
- if xconfig['capture']
29
- root = root.at(xconfig['capture'])
30
- end
31
- split = xconfig['split']
32
34
  xconfig.delete('capture')
33
35
  xconfig.delete('split')
34
36
 
35
- root.search(split).each do |element|
36
- item = RSS::RDF::Item.new
37
-
38
- extract_attribute_from element, item
37
+ urls.each do |url|
38
+ logger.debug("Process: #{url}")
39
+ page = agent.get(url)
40
+ root = page.root
41
+
42
+ if capture
43
+ root = root.at(capture)
44
+ end
45
+
46
+ root.search(split).each do |element|
47
+ item = RSS::RDF::Item.new
48
+
49
+ extract_attribute_from element, item, binding
39
50
 
40
- data << item
51
+ data << item
52
+ end
53
+ sleep wait
41
54
  end
42
55
 
43
56
  data
@@ -47,7 +47,7 @@ module Yapra::Plugin::Filter
47
47
  item = new_item
48
48
  end
49
49
 
50
- extract_attribute_from page.root, item
50
+ extract_attribute_from page.root, item, binding
51
51
 
52
52
  end
53
53
  item
@@ -20,8 +20,11 @@ module Yapra::Plugin::Publish
20
20
  #
21
21
  class Gmail < Yapra::Plugin::Publish::Imap
22
22
  protected
23
- def create_imap server, port, usessl
24
- Net::IMAP.new('imap.gmail.com', 993, true)
23
+ def prepare
24
+ super
25
+ config['imap_server'] = 'imap.gmail.com'
26
+ config['port'] = 993
27
+ config['ssl'] = true
25
28
  end
26
29
  end
27
- end
30
+ end
@@ -1,6 +1,5 @@
1
1
  require 'net/imap'
2
- require 'yapra/version'
3
- require 'yapra/plugin/base'
2
+ require 'yapra/plugin/publish/mail'
4
3
 
5
4
  module Yapra::Plugin::Publish
6
5
  # = module: Publish::Imap -- Yuanying
@@ -23,114 +22,32 @@ module Yapra::Plugin::Publish
23
22
  # #from: 'test@example.com'
24
23
  # to: 'test2@example.com'
25
24
  #
26
- class Imap < Yapra::Plugin::Base
27
- def run(data)
28
- username = config['username']
29
- password = config['password']
30
- server = config['imap_server'] || 'imap.gmail.com'
31
- port = config['port'] || 993
32
- usessl = ('off' != config['ssl'])
33
- mailbox = config['mailbox'] || 'inbox'
34
- wait = config['wait'] || 1
35
-
36
- unless config['mail']
37
- config['mail'] = {}
38
- end
39
- subject_prefix = config['mail']['subject_prefix'] || ''
40
- from = config['mail']['from'] || 'yapra@localhost'
41
- to = config['mail']['to'] || 'me@localhost'
42
-
43
- imap = create_imap server, port, usessl
44
- logger.debug(imap.greeting)
45
-
46
- imap.login(username, password)
47
- logger.info('imap login was succeed.')
48
- imap.examine(mailbox)
49
- data.each do |item|
50
- date = item.date || item.dc_date || Time.now
51
- content = item.content_encoded || item.description || 'from Yapra.'
52
- content = [content].pack('m')
53
- if config['mail']['from_template']
54
- from = apply_template(config['mail']['from_template'], binding)
55
- end
56
- if config['mail']['to_template']
57
- to = apply_template(config['mail']['to_template'], binding)
58
- end
59
- subject = (subject_prefix + item.title).gsub(/\n/, '').chomp
60
- logger.debug("try append item: #{subject}")
61
- boundary = "----_____====#{Time.now.to_i}--BOUDARY"
62
- attachments = create_attachments(item, config)
63
- imap.append(mailbox, apply_template(mail_template, binding), nil, date)
64
- # puts apply_template(mail_template, binding)
65
-
66
- sleep wait
67
- end
68
- imap.disconnect
69
-
70
- data
71
- end
72
-
25
+ class Imap < Mail
73
26
  protected
74
- def create_imap server, port, usessl
75
- logger.debug("server: #{server}:#{port}, usessl = #{usessl}")
76
- Net::IMAP.new(server, port, usessl)
27
+ def prepare
28
+ super
29
+ config['imap_server'] = config['imap_server'] || 'imap.gmail.com'
30
+ config['port'] = config['port'] || 993
31
+ config['ssl'] = ('off' != config['ssl'])
32
+ config['mailbox'] = config['mailbox'] || 'inbox'
77
33
  end
78
-
79
- def encode_field field
80
- field.gsub(/[^\x01-\x7f]*/) {|x|
81
- x.scan(/.{1,10}/).map {|y|
82
- "=?UTF-8?B?" + y.to_a.pack('m').chomp + "?="
83
- }.join("\n ")
84
- }
85
- end
86
-
87
- def create_attachments item, config
88
- attachments = []
89
- attachment_attributes = config['mail']['attachments']
90
- if attachment_attributes.kind_of?(String)
91
- file = item.__send__(attachment_attributes)
92
- attachments << file if file.kind_of?(WWW::Mechanize::File)
93
- elsif attachment_attributes.kind_of?(Array)
94
- attachment_attributes.each do |atc|
95
- file = item.__send__(atc)
96
- attachments << file if file.kind_of?(WWW::Mechanize::File)
97
- end
98
- end
99
- attachments
100
- end
101
-
102
- def mail_template
103
- return <<EOT
104
- From: <%=encode_field(from) %>
105
- To: <%=encode_field(to) %>
106
- Date: <%=date.rfc2822 %>
107
- MIME-Version: 1.0
108
- X-Mailer: Yapra <%=Yapra::VERSION::STRING %>
109
- Subject: <%=encode_field(subject) %>
110
- Content-Type: multipart/mixed; boundary="<%=boundary -%>"
111
-
112
- This is a multi-part message in MIME format.
113
34
 
114
- --<%=boundary %>
115
- Content-type: text/html; charset=UTF-8
116
- Content-transfer-encoding: base64
117
-
118
- <%=content %>
119
-
120
- --<%=boundary %>
121
- <% attachments.each do |file| -%>
122
- Content-Type: <%=file.header['Content-Type'] %>;
123
- name="<%=encode_field(file.filename) %>"
124
- Content-Disposition: attachment;
125
- filename="<%=encode_field(file.filename) %>"
126
- Content-Transfer-Encoding: base64
127
-
128
- <%=[file.body].pack('m') -%>
35
+ def open_session
36
+ logger.debug("server: #{config['imap_server']}:#{config['port']}, usessl = #{config['ssl']}")
37
+ imap = Net::IMAP.new(config['imap_server'], config['port'], config['ssl'])
38
+ logger.debug(imap.greeting)
39
+ imap.login(config['username'], config['password'])
40
+ logger.info('imap login was succeed.')
41
+ imap.examine(config['mailbox'])
42
+ @session = imap
43
+ end
129
44
 
130
- --<%=boundary %>
45
+ def close_session
46
+ @session.disconnect
47
+ end
131
48
 
132
- <% end -%>
133
- EOT
49
+ def send_item(msg, opt)
50
+ @session.append(config['mailbox'], msg, nil, opt['date'])
134
51
  end
135
52
  end
136
- end
53
+ end