webfeed 0.0.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/MIT-LICENSE +20 -0
- data/README.rdoc +49 -0
- data/Rakefile +27 -0
- data/lib/feed_reader.rb +36 -0
- data/lib/generators/web_feed/add_image_generator.rb +15 -0
- data/lib/generators/web_feed/install_generator.rb +89 -0
- data/lib/generators/web_feed/keyword_generator.rb +15 -0
- data/lib/generators/web_feed/news_generator.rb +15 -0
- data/lib/generators/web_feed/resource_generator.rb +15 -0
- data/lib/generators/web_feed/templates/controllers/keywords_controller.rb.erb +34 -0
- data/lib/generators/web_feed/templates/controllers/news_controller.rb.erb +24 -0
- data/lib/generators/web_feed/templates/controllers/resources_controller.rb.erb +40 -0
- data/lib/generators/web_feed/templates/migrations/add_attachment_image_to_news.rb.erb +15 -0
- data/lib/generators/web_feed/templates/migrations/create_keywords.rb.erb +10 -0
- data/lib/generators/web_feed/templates/migrations/create_news.rb.erb +14 -0
- data/lib/generators/web_feed/templates/migrations/create_resources.rb.erb +12 -0
- data/lib/generators/web_feed/templates/models/keyword.rb.erb +17 -0
- data/lib/generators/web_feed/templates/models/news.rb.erb +26 -0
- data/lib/generators/web_feed/templates/models/resource.rb.erb +27 -0
- data/lib/generators/web_feed/templates/stylesheets/webfeed.css +144 -0
- data/lib/generators/web_feed/templates/views/keywords/_form.html.erb +28 -0
- data/lib/generators/web_feed/templates/views/keywords/edit.html.erb +2 -0
- data/lib/generators/web_feed/templates/views/keywords/index.html.erb +14 -0
- data/lib/generators/web_feed/templates/views/keywords/new.html.erb +2 -0
- data/lib/generators/web_feed/templates/views/layouts/_webfeed.html.erb +5 -0
- data/lib/generators/web_feed/templates/views/layouts/webfeed.html.erb +11 -0
- data/lib/generators/web_feed/templates/views/news/index.html.erb +16 -0
- data/lib/generators/web_feed/templates/views/news/show.html.erb +9 -0
- data/lib/generators/web_feed/templates/views/resources/_form.html.erb +34 -0
- data/lib/generators/web_feed/templates/views/resources/edit.html.erb +2 -0
- data/lib/generators/web_feed/templates/views/resources/index.html.erb +29 -0
- data/lib/generators/web_feed/templates/views/resources/new.html.erb +2 -0
- data/lib/tasks/webfeed_tasks.rake +4 -0
- data/lib/webfeed/version.rb +3 -0
- data/lib/webfeed.rb +4 -0
- metadata +201 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
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.rdoc
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
= Webfeed
|
2
|
+
|
3
|
+
This project uses MIT-LICENSE.
|
4
|
+
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
In <b>Rails 3</b>, add following line to your Gemfile and run the <tt>bundle</tt> command.
|
9
|
+
|
10
|
+
gem "web_feed"
|
11
|
+
|
12
|
+
In <b>Rails 2</b>, add following line to your environment.rb file.
|
13
|
+
|
14
|
+
config.gem "web_feed"
|
15
|
+
|
16
|
+
== Getting Started
|
17
|
+
|
18
|
+
There couple of generators. you can run something like <tt>rails g web_feed:install -h</tt> to see what they do
|
19
|
+
|
20
|
+
web_feed:install
|
21
|
+
web_feed:resource
|
22
|
+
web_feed:keyword
|
23
|
+
web_feed:news
|
24
|
+
web_feed:add_image
|
25
|
+
|
26
|
+
Running <tt>rails g web_feed:install -mvc</tt> will create all migrations, models, views, controllers and routings and a basic stylesheet file.
|
27
|
+
|
28
|
+
In case you want to rename the entities you can run this command:
|
29
|
+
|
30
|
+
rails g web_feed:install -r [RESOURCE_NAME] -n [NEWS_NAME] -k [KEYWORD_NAME] -mvc
|
31
|
+
rails g web_feed:install -r resource -n post -k keyword -mvc
|
32
|
+
|
33
|
+
=== Basic View
|
34
|
+
|
35
|
+
Add following line to your main layout to see the WebFeed pages with basic styling
|
36
|
+
|
37
|
+
<%= stylesheet_link_tag "webfeed", :media => "all" %>
|
38
|
+
|
39
|
+
And add this line to see the what pages you have in WebFeed
|
40
|
+
|
41
|
+
<%= render 'layouts/webfeed' %>
|
42
|
+
|
43
|
+
=== Try It
|
44
|
+
|
45
|
+
After generating file and migrating <tt>rails db:migrate</tt>. Try to add some RSS resources such as <i>http://feeds.gizmodo.com.au/GizmodoAustralia</i> or <i>http://techcrunch.com/feed/</i> and some keywords such as <i>iphone</i>, <i>samsung</i> and <i>facebook</i>. Then try to update resources from index page.
|
46
|
+
|
47
|
+
== Testing SPECS
|
48
|
+
|
49
|
+
bundle exec guard
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'Webfeed'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
data/lib/feed_reader.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module FeedReader
|
2
|
+
|
3
|
+
require 'open-uri'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
class Reader
|
7
|
+
|
8
|
+
attr_accessor :list
|
9
|
+
|
10
|
+
def initialize(uri)
|
11
|
+
@doc = Nokogiri::XML(open(uri))
|
12
|
+
@list = []
|
13
|
+
@doc.css('item').each do |item|
|
14
|
+
@list << [ item.at_css('title').text, ActionController::Base.helpers.sanitize(item.at_css('description').text,:tags=>[]), Nokogiri::HTML(item.css('description').text).at_css('img').attributes['src'].value, item.at_css('link').text ] # title, description, image, link
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def filter( inc_words, exc_words=[] )
|
19
|
+
template = '\W(?)\W'
|
20
|
+
inc = template.gsub '?', inc_words.join('|')
|
21
|
+
exc = template.gsub '?', exc_words.join('|')
|
22
|
+
list = []
|
23
|
+
@list.each do |item|
|
24
|
+
str = " #{item[0]} #{item[1]} "
|
25
|
+
if inc_words.empty? || !(str =~ Regexp.new(inc,'i')).nil?
|
26
|
+
if exc_words.empty? || (str =~ Regexp.new(inc,'i')).nil?
|
27
|
+
list<<item
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
list
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module WebFeed
|
4
|
+
|
5
|
+
class AddImageGenerator < ActiveRecord::Generators::Base
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def generate_migration
|
10
|
+
migration_template "migrations/add_attachment_image_to_news.rb.erb", "db/migrate/add_attachment_image_to_#{name.downcase.underscore.pluralize}.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
module WebFeed
|
4
|
+
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
|
7
|
+
class_option :resource , :type => :string, :desc => 'Change the name for resources' , :default => 'resource' , :aliases => '-r'
|
8
|
+
class_option :keyword , :type => :string, :desc => 'Change the name for keywords' , :default => 'keyword' , :aliases => '-k'
|
9
|
+
class_option :news , :type => :string, :desc => 'Change the name for news' , :default => 'news' , :aliases => '-n'
|
10
|
+
|
11
|
+
class_option :include_models , :type => :boolean, :desc => 'Create model files' , :aliases => '-m'
|
12
|
+
class_option :include_controllers , :type => :boolean, :desc => 'Create controller files' , :aliases => '-c'
|
13
|
+
class_option :include_views , :type => :boolean, :desc => 'Create view files' , :aliases => '-v'
|
14
|
+
|
15
|
+
desc "Create routes, migrations, models, controllers, views"
|
16
|
+
|
17
|
+
source_root File.expand_path('../templates', __FILE__)
|
18
|
+
|
19
|
+
def init
|
20
|
+
route <<-RES
|
21
|
+
resources :#{resource.pluralize} do
|
22
|
+
member do
|
23
|
+
post :read
|
24
|
+
end
|
25
|
+
end
|
26
|
+
RES
|
27
|
+
route <<-NEWS
|
28
|
+
resources :#{news.pluralize} do
|
29
|
+
member do
|
30
|
+
get "/:title(.:format)", :action => :show, :as => 'read'
|
31
|
+
post :publish
|
32
|
+
post :unpublish
|
33
|
+
end
|
34
|
+
end
|
35
|
+
NEWS
|
36
|
+
route "resources :#{keyword.pluralize}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_migration
|
40
|
+
generate "web_feed:resource #{resource}"
|
41
|
+
generate "web_feed:news #{news}"
|
42
|
+
generate "web_feed:keyword #{keyword}"
|
43
|
+
generate "web_feed:add_image #{news}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_app
|
47
|
+
if options.include_models?
|
48
|
+
template "models/resource.rb.erb", "#{Rails.root}/app/models/#{resource}.rb"
|
49
|
+
template "models/news.rb.erb", "#{Rails.root}/app/models/#{news}.rb"
|
50
|
+
template "models/keyword.rb.erb", "#{Rails.root}/app/models/#{keyword}.rb"
|
51
|
+
end
|
52
|
+
if options.include_controllers?
|
53
|
+
template "controllers/resources_controller.rb.erb", "#{Rails.root}/app/controllers/#{resource.pluralize}_controller.rb"
|
54
|
+
template "controllers/news_controller.rb.erb", "#{Rails.root}/app/controllers/#{news.pluralize}_controller.rb"
|
55
|
+
template "controllers/keywords_controller.rb.erb", "#{Rails.root}/app/controllers/#{keyword.pluralize}_controller.rb"
|
56
|
+
end
|
57
|
+
if options.include_views?
|
58
|
+
%w( index new edit _form).each do |file|
|
59
|
+
template "views/resources/#{file}.html.erb", "#{Rails.root}/app/views/#{resource.pluralize}/#{file}.html.erb"
|
60
|
+
end
|
61
|
+
%w( index new edit _form).each do |file|
|
62
|
+
template "views/keywords/#{file}.html.erb", "#{Rails.root}/app/views/#{keyword.pluralize}/#{file}.html.erb"
|
63
|
+
end
|
64
|
+
%w( index show).each do |file|
|
65
|
+
template "views/news/#{file}.html.erb", "#{Rails.root}/app/views/#{news.pluralize}/#{file}.html.erb"
|
66
|
+
end
|
67
|
+
copy_file "views/layouts/webfeed.html.erb", "#{Rails.root}/app/views/layouts/webfeed.html.erb"
|
68
|
+
template "views/layouts/_webfeed.html.erb", "#{Rails.root}/app/views/layouts/_webfeed.html.erb"
|
69
|
+
copy_file "stylesheets/webfeed.css", "#{Rails.root}/app/assets/stylesheets/webfeed.css"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def resource
|
76
|
+
options.resource.downcase.singularize
|
77
|
+
end
|
78
|
+
|
79
|
+
def keyword
|
80
|
+
options.keyword.downcase.singularize
|
81
|
+
end
|
82
|
+
|
83
|
+
def news
|
84
|
+
options.news.downcase.singularize
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module WebFeed
|
4
|
+
|
5
|
+
class KeywordGenerator < ActiveRecord::Generators::Base
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def generate_migration
|
10
|
+
migration_template "migrations/create_keywords.rb.erb", "db/migrate/create_#{name.downcase.underscore.pluralize}.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module WebFeed
|
4
|
+
|
5
|
+
class NewsGenerator < ActiveRecord::Generators::Base
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def generate_migration
|
10
|
+
migration_template "migrations/create_news.rb.erb", "db/migrate/create_#{name.downcase.underscore.pluralize}.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module WebFeed
|
4
|
+
|
5
|
+
class ResourceGenerator < ActiveRecord::Generators::Base
|
6
|
+
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
|
9
|
+
def generate_migration
|
10
|
+
migration_template "migrations/create_resources.rb.erb", "db/migrate/create_#{name.downcase.underscore.pluralize}.rb"
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class <%= keyword.pluralize.camelcase %>Controller < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
@positive = <%= keyword.camelcase %>.includables
|
5
|
+
@negative = <%= keyword.camelcase %>.excludables
|
6
|
+
end
|
7
|
+
|
8
|
+
def new
|
9
|
+
@keyword = <%= keyword.camelcase %>.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def create
|
13
|
+
@keyword = <%= keyword.camelcase %>.new params[:<%=keyword%>]
|
14
|
+
if @keyword.save
|
15
|
+
redirect_to root_path
|
16
|
+
else
|
17
|
+
render :new
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def edit
|
22
|
+
@keyword = <%= keyword.camelcase %>.find params[:id]
|
23
|
+
end
|
24
|
+
|
25
|
+
def update
|
26
|
+
@keyword = Keyword.find params[:id]
|
27
|
+
if @keyword.update_attributes(params[:<%=keyword%>])
|
28
|
+
redirect_to root_path
|
29
|
+
else
|
30
|
+
render :edit
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class <%= news.pluralize.camelcase %>Controller < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
@news = <%= news.camelcase %>.all
|
5
|
+
end
|
6
|
+
|
7
|
+
def show
|
8
|
+
@news = <%= news.camelcase %>.find params[:id]
|
9
|
+
render :layout => 'webfeed'
|
10
|
+
end
|
11
|
+
|
12
|
+
def publish
|
13
|
+
@news = <%= news.camelcase %>.find params[:id]
|
14
|
+
@news.update_attributes( :is_published => true )
|
15
|
+
redirect_to root_path
|
16
|
+
end
|
17
|
+
|
18
|
+
def unpublish
|
19
|
+
@news = <%= news.camelcase %>.find params[:id]
|
20
|
+
@news.update_attributes( :is_published => false )
|
21
|
+
redirect_to root_path
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class <%= resource.pluralize.camelcase %>Controller < ApplicationController
|
2
|
+
|
3
|
+
def index
|
4
|
+
@expired = <%= resource.camelcase %>.expired
|
5
|
+
@uptodated = <%= resource.camelcase %>.uptodated
|
6
|
+
end
|
7
|
+
|
8
|
+
def read
|
9
|
+
@resource = <%= resource.camelcase %>.find params[:id]
|
10
|
+
@resource.read_and_update
|
11
|
+
redirect_to <%=resource.pluralize%>_path
|
12
|
+
end
|
13
|
+
|
14
|
+
def new
|
15
|
+
@resource = <%= resource.camelcase %>.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
@resource = <%= resource.camelcase %>.new params[:<%=resource%>]
|
20
|
+
if @resource.save
|
21
|
+
redirect_to <%=resource.pluralize%>_path
|
22
|
+
else
|
23
|
+
render :new
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def edit
|
28
|
+
@resource = <%= resource.camelcase %>.find params[:id]
|
29
|
+
end
|
30
|
+
|
31
|
+
def update
|
32
|
+
@resource = <%= resource.camelcase %>.find params[:id]
|
33
|
+
if @resource.update_attributes(params[:<%=resource%>])
|
34
|
+
redirect_to <%=resource.pluralize%>_path
|
35
|
+
else
|
36
|
+
render :edit
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
add_column :<%= table_name %>, :image_file_name, :string
|
4
|
+
add_column :<%= table_name %>, :image_content_type, :string
|
5
|
+
add_column :<%= table_name %>, :image_file_size, :integer
|
6
|
+
add_column :<%= table_name %>, :image_updated_at, :datetime
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.down
|
10
|
+
remove_column :<%= table_name %>, :image_file_name
|
11
|
+
remove_column :<%= table_name %>, :image_content_type
|
12
|
+
remove_column :<%= table_name %>, :image_file_size
|
13
|
+
remove_column :<%= table_name %>, :image_updated_at
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :<%= table_name %> do |t|
|
4
|
+
t.string :title
|
5
|
+
t.text :description
|
6
|
+
t.string :url
|
7
|
+
t.string :image_url
|
8
|
+
t.boolean :is_published, :default => false
|
9
|
+
t.string :uuid, :null => false
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class <%= keyword.camelcase %> < ActiveRecord::Base
|
2
|
+
attr_accessible :is_negative, :phrase
|
3
|
+
|
4
|
+
validates_presence_of :phrase
|
5
|
+
|
6
|
+
scope :excludables, where( 'is_negative IS TRUE' )
|
7
|
+
scope :includables, where( 'is_negative IS NOT TRUE' )
|
8
|
+
|
9
|
+
def self.includables_list
|
10
|
+
<%= keyword.camelcase %>.includables.collect{ |i| i=i.phrase }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.excludables_list
|
14
|
+
<%= keyword.camelcase %>.excludables.collect{ |i| i=i.phrase }
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class <%= news.camelcase %> < ActiveRecord::Base
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
require "open-uri"
|
5
|
+
|
6
|
+
attr_accessible :description, :image, :image_url, :title, :url, :is_published
|
7
|
+
has_attached_file :image, :styles => { :thumb => "100x80>", :url => "/system/:class/:id/:style/:filename" }
|
8
|
+
|
9
|
+
validates_presence_of :title, :url
|
10
|
+
validates_uniqueness_of :uuid, :on => :create
|
11
|
+
|
12
|
+
default_scope :order => 'created_at DESC'
|
13
|
+
|
14
|
+
scope :published, where("is_published IS TRUE")
|
15
|
+
|
16
|
+
def url=(url)
|
17
|
+
write_attribute :url, url
|
18
|
+
self.uuid = Digest::MD5.hexdigest(url)
|
19
|
+
end
|
20
|
+
|
21
|
+
def image_url=(url)
|
22
|
+
write_attribute :image_url, url
|
23
|
+
self.image = open(url)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class <%= resource.camelcase %> < ActiveRecord::Base
|
2
|
+
|
3
|
+
attr_accessible :frequency, :name, :url, :checked_at
|
4
|
+
|
5
|
+
validates_presence_of :url, :frequency
|
6
|
+
|
7
|
+
scope :expired, where("checked_at IS NULL OR TIMESTAMPDIFF(MINUTE, checked_at, '#{DateTime.now.utc}') > frequency")
|
8
|
+
scope :uptodated, where("TIMESTAMPDIFF(MINUTE, checked_at, '#{DateTime.now.utc}') <= frequency")
|
9
|
+
|
10
|
+
def read
|
11
|
+
if self.checked_at.nil? || (DateTime.now.to_i - DateTime.parse(self.checked_at.utc.to_s).to_i)/60 > self.frequency
|
12
|
+
reader = FeedReader::Reader.new self.url
|
13
|
+
news = reader.filter <%= keyword.camelcase %>.includables_list
|
14
|
+
end
|
15
|
+
news
|
16
|
+
end
|
17
|
+
|
18
|
+
def read_and_update
|
19
|
+
items = read
|
20
|
+
items.each do |item|
|
21
|
+
<%= news.camelcase %>.create :title => item[0], :description => item[1], :image_url => item[2], :url => item[3]
|
22
|
+
end
|
23
|
+
update_attributes( :checked_at => DateTime.now )
|
24
|
+
items
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
9
|
+
* compiled file, but it's generally better to create a new file per style scope.
|
10
|
+
*
|
11
|
+
*= require_self
|
12
|
+
*= require_tree .
|
13
|
+
*/
|
14
|
+
body{
|
15
|
+
font-family: arial, tahoma;
|
16
|
+
font-size: 12px;
|
17
|
+
color: #111;
|
18
|
+
}
|
19
|
+
.menu{
|
20
|
+
background: #222;
|
21
|
+
font-size: 14px;
|
22
|
+
padding: 10px;
|
23
|
+
}
|
24
|
+
.menu a{
|
25
|
+
padding: 5px;
|
26
|
+
margin: 0px 10px;
|
27
|
+
color: #fff;
|
28
|
+
font-weight: bold;
|
29
|
+
text-decoration: none;
|
30
|
+
}
|
31
|
+
.menu a:hover{
|
32
|
+
background: #000;
|
33
|
+
}
|
34
|
+
h1,h2,h3,h4,h5{
|
35
|
+
font-size: 12px;
|
36
|
+
font-weight: bold;
|
37
|
+
color: #1975D1;
|
38
|
+
margin: 0px;
|
39
|
+
padding: 6px 0px 2px;
|
40
|
+
}
|
41
|
+
a{
|
42
|
+
color: #1975D1;
|
43
|
+
}
|
44
|
+
h1,
|
45
|
+
h1 a{
|
46
|
+
font-size: 22px;
|
47
|
+
color: #2D519B;
|
48
|
+
}
|
49
|
+
h1 a,h2 a,h3 a,h4 a,h5 a{ text-decoration: none; }
|
50
|
+
h1 a:hover,h2 a:hover,h3 a:hover,h4 a:hover,h5 a:hover{ text-decoration: underline; }
|
51
|
+
h2{
|
52
|
+
font-size: 18px;
|
53
|
+
color: #D69808;
|
54
|
+
}
|
55
|
+
h3{
|
56
|
+
font-size: 16px;
|
57
|
+
color: #D6083B;
|
58
|
+
}
|
59
|
+
h4{
|
60
|
+
font-size: 14px;
|
61
|
+
color: #222;
|
62
|
+
}
|
63
|
+
h4, h5{
|
64
|
+
padding: 2px 0px 0px;
|
65
|
+
}
|
66
|
+
.inline{
|
67
|
+
display: inline-block;
|
68
|
+
*display: inline;
|
69
|
+
*zoom: 1;
|
70
|
+
}
|
71
|
+
.resource,
|
72
|
+
.news,
|
73
|
+
.keyword{
|
74
|
+
border: #111 1px dashed;
|
75
|
+
background: #eee;
|
76
|
+
padding: 5px;
|
77
|
+
margin: 2px;
|
78
|
+
}
|
79
|
+
.news.published{
|
80
|
+
background: #EAD144;
|
81
|
+
}
|
82
|
+
.resource:hover,
|
83
|
+
.news:hover,
|
84
|
+
.keyword:hover{
|
85
|
+
background: #aaa;
|
86
|
+
}
|
87
|
+
.resource .frequency{
|
88
|
+
font-size: 12px;
|
89
|
+
font-weight: bold;
|
90
|
+
color: #1975D1;
|
91
|
+
}
|
92
|
+
.resource form{ display: inline; }
|
93
|
+
.resource a,
|
94
|
+
.keyword a{
|
95
|
+
color: #444;
|
96
|
+
padding: 0px 5px;
|
97
|
+
}
|
98
|
+
.errors{
|
99
|
+
background: #B22323;
|
100
|
+
border: #6D0303 1px solid;
|
101
|
+
color: #fff;
|
102
|
+
padding: 10px;
|
103
|
+
font-weight: bold;
|
104
|
+
}
|
105
|
+
.errors h2{
|
106
|
+
color: #fff;
|
107
|
+
}
|
108
|
+
.daily_header{
|
109
|
+
height: 140px;
|
110
|
+
border-bottom: #eee 3px solid;
|
111
|
+
background: #222;
|
112
|
+
color: #fff;
|
113
|
+
padding: 0px 10px;
|
114
|
+
}
|
115
|
+
.daily_header h2{
|
116
|
+
padding: 0px 0px 10px;
|
117
|
+
}
|
118
|
+
.daily_reader{
|
119
|
+
position: absolute;
|
120
|
+
top: 143px;
|
121
|
+
bottom: 0px;
|
122
|
+
width: 100%;
|
123
|
+
}
|
124
|
+
.daily_reader iframe{
|
125
|
+
width: 100%;
|
126
|
+
height: 100%;
|
127
|
+
}
|
128
|
+
body.daily{
|
129
|
+
overflow: hidden;
|
130
|
+
margin: 0px;
|
131
|
+
padding: 0px;
|
132
|
+
}
|
133
|
+
.desc{
|
134
|
+
width: 800px;
|
135
|
+
vertical-align: top;
|
136
|
+
margin: 0px;
|
137
|
+
padding: 0px 10px;
|
138
|
+
}
|
139
|
+
.daily_header h1 span{
|
140
|
+
color: #E5D600;
|
141
|
+
}
|
142
|
+
.daily_header .desc{
|
143
|
+
width: 500px;
|
144
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<%%= form_for @keyword do |f| %>
|
2
|
+
<%% if @keyword.errors.any? %>
|
3
|
+
<div class="errors">
|
4
|
+
<h2><%%= pluralize(@keyword.errors.count, "error") %> prohibited this keyword from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<%% @keyword.errors.full_messages.each do |msg| %>
|
8
|
+
<li><%%= msg %></li>
|
9
|
+
<%% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<%% end %>
|
13
|
+
<div>
|
14
|
+
<%%= f.label :phrase %>
|
15
|
+
</div>
|
16
|
+
<div>
|
17
|
+
<%%= f.text_field :phrase %>
|
18
|
+
</div>
|
19
|
+
<div>
|
20
|
+
<%%= f.label :is_negative %>
|
21
|
+
</div>
|
22
|
+
<div>
|
23
|
+
<%%= f.check_box :is_negative %>
|
24
|
+
</div>
|
25
|
+
<div>
|
26
|
+
<%%= f.submit %> | <a href='<%%=<%=keyword.pluralize%>_path%>'>back</a>
|
27
|
+
</div>
|
28
|
+
<%%end%>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<h1>Keywords</h1>
|
2
|
+
<div class='menu'>
|
3
|
+
<a href='<%%=new_<%=keyword%>_path%>'>Add keyword</a>
|
4
|
+
</div>
|
5
|
+
<h2>Inclusive</h2>
|
6
|
+
<%%@positive.each do |keyword|%>
|
7
|
+
<div class='keyword'><%%=keyword.phrase%> | <a href='<%%=edit_<%=keyword%>_path keyword.id%>'>Edit</a>
|
8
|
+
</div>
|
9
|
+
<%%end%>
|
10
|
+
<h2>Exclusive</h2>
|
11
|
+
<%%@negative.each do |keyword|%>
|
12
|
+
<div class='keyword'><%%=keyword.phrase%> | <a href='<%%=edit_<%=keyword%>_path keyword.id%>'>Edit</a>
|
13
|
+
</div>
|
14
|
+
<%%end%>
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h1>News</h1>
|
2
|
+
<%% @news.each do |news| %>
|
3
|
+
<div class='news <%%= 'published' if news.is_published %>'>
|
4
|
+
<h2><a href='<%%= "#{read_<%=news%>_path(news.id, news.title.gsub(/\W+/, '-'))}.html" %>'><%%= news.title %></a></h2>
|
5
|
+
<img src='<%%= news.image.url(:thumb) %>'/><p class='inline desc'><%%= news.description.html_safe %></p>
|
6
|
+
<%%unless news.is_published%>
|
7
|
+
<%%= form_tag publish_<%=news%>_path(news.id) %>
|
8
|
+
<button>Publish</button>
|
9
|
+
</form>
|
10
|
+
<%%else%>
|
11
|
+
<%%= form_tag unpublish_<%=news%>_path(news.id) %>
|
12
|
+
<button>Unpublish</button>
|
13
|
+
</form>
|
14
|
+
<%%end%>
|
15
|
+
</div>
|
16
|
+
<%%end%>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<div class='daily_header'>
|
2
|
+
<h1><a href='<%%= <%=news%>_path %>'>Read More News <span>@ WebFeed</span></a></h1>
|
3
|
+
<h2><a href='<%%=@news.url%>' target='_blank'><%%= @news.title %></a></h2>
|
4
|
+
<img src='<%%= @news.image.url(:thumb) %>'/>
|
5
|
+
<p class='inline desc'><%%= truncate @news.description, :length => 400 %></p>
|
6
|
+
</div>
|
7
|
+
<div class='daily_reader'>
|
8
|
+
<iframe frameborder='0' src='<%%=@news.url%>'></iframe>
|
9
|
+
</div>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<%%= form_for @resource do |f| %>
|
2
|
+
<%% if @resource.errors.any? %>
|
3
|
+
<div class="errors">
|
4
|
+
<h2><%%= pluralize(@resource.errors.count, "error") %> prohibited this resource from being saved:</h2>
|
5
|
+
|
6
|
+
<ul>
|
7
|
+
<%% @resource.errors.full_messages.each do |msg| %>
|
8
|
+
<li><%%= msg %></li>
|
9
|
+
<%% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
<%% end %>
|
13
|
+
<div>
|
14
|
+
<%%= f.label :name %>
|
15
|
+
</div>
|
16
|
+
<div>
|
17
|
+
<%%= f.text_field :name %>
|
18
|
+
</div>
|
19
|
+
<div>
|
20
|
+
<%%= f.label :url %>
|
21
|
+
</div>
|
22
|
+
<div>
|
23
|
+
<%%= f.text_field :url %>
|
24
|
+
</div>
|
25
|
+
<div>
|
26
|
+
<%%= f.label :frequency %>
|
27
|
+
</div>
|
28
|
+
<div>
|
29
|
+
<%%= f.text_field :frequency %>
|
30
|
+
</div>
|
31
|
+
<div>
|
32
|
+
<%%= f.submit %> | <a href='<%%=<%=resource.pluralize%>_path%>'>back</a>
|
33
|
+
</div>
|
34
|
+
<%%end%>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<h1>Resources</h1>
|
2
|
+
<div class='menu'>
|
3
|
+
<a href='<%%=new_<%=resource%>_path%>'>Add Resource</a>
|
4
|
+
</div>
|
5
|
+
<div>
|
6
|
+
<h2>Expired Resources</h2>
|
7
|
+
<%%@expired.each do |resource|%>
|
8
|
+
<div class='resource'>
|
9
|
+
<h3><%%=resource.name%></h3>
|
10
|
+
<h4><%%=resource.url%></h4>
|
11
|
+
<div class='frequency'>every <%%=resource.frequency%> minutes
|
12
|
+
<%%= form_tag read_<%=resource%>_path(resource.id) %>
|
13
|
+
<button>Update</button>
|
14
|
+
</form>
|
15
|
+
| <a href='<%%= edit_<%=resource%>_path resource.id %>'>Edit</a>
|
16
|
+
</div>
|
17
|
+
</div>
|
18
|
+
<%%end%>
|
19
|
+
<h2>Recently Checked Resources</h2>
|
20
|
+
<%%@uptodated.each do |resource|%>
|
21
|
+
<div class='resource'>
|
22
|
+
<h3><%%=resource.name%></h3>
|
23
|
+
<h4><%%=resource.url%></h4>
|
24
|
+
<div class='frequency'>every <%%=resource.frequency%> minutes
|
25
|
+
| <a href='<%%= edit_<%=resource%>_path resource.id %>'>Edit</a>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
<%%end%>
|
29
|
+
</div>
|
data/lib/webfeed.rb
ADDED
metadata
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: webfeed
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Arash Karimzadeh
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-09-06 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rails
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 31
|
29
|
+
segments:
|
30
|
+
- 3
|
31
|
+
- 2
|
32
|
+
- 8
|
33
|
+
version: 3.2.8
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: mysql2
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :development
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: rspec-rails
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :development
|
63
|
+
version_requirements: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: capybara
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 3
|
73
|
+
segments:
|
74
|
+
- 0
|
75
|
+
version: "0"
|
76
|
+
type: :development
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard-rspec
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
type: :development
|
91
|
+
version_requirements: *id005
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: guard-spork
|
94
|
+
prerelease: false
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
type: :development
|
105
|
+
version_requirements: *id006
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: rb-inotify
|
108
|
+
prerelease: false
|
109
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ~>
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 47
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
- 8
|
118
|
+
- 8
|
119
|
+
version: 0.8.8
|
120
|
+
type: :development
|
121
|
+
version_requirements: *id007
|
122
|
+
description: Read feeds from all around the world and publish them within your website
|
123
|
+
email:
|
124
|
+
- arash@tectual.com.au
|
125
|
+
executables: []
|
126
|
+
|
127
|
+
extensions: []
|
128
|
+
|
129
|
+
extra_rdoc_files: []
|
130
|
+
|
131
|
+
files:
|
132
|
+
- lib/tasks/webfeed_tasks.rake
|
133
|
+
- lib/webfeed/version.rb
|
134
|
+
- lib/generators/web_feed/add_image_generator.rb
|
135
|
+
- lib/generators/web_feed/keyword_generator.rb
|
136
|
+
- lib/generators/web_feed/install_generator.rb
|
137
|
+
- lib/generators/web_feed/templates/models/news.rb.erb
|
138
|
+
- lib/generators/web_feed/templates/models/resource.rb.erb
|
139
|
+
- lib/generators/web_feed/templates/models/keyword.rb.erb
|
140
|
+
- lib/generators/web_feed/templates/migrations/create_keywords.rb.erb
|
141
|
+
- lib/generators/web_feed/templates/migrations/create_resources.rb.erb
|
142
|
+
- lib/generators/web_feed/templates/migrations/add_attachment_image_to_news.rb.erb
|
143
|
+
- lib/generators/web_feed/templates/migrations/create_news.rb.erb
|
144
|
+
- lib/generators/web_feed/templates/controllers/keywords_controller.rb.erb
|
145
|
+
- lib/generators/web_feed/templates/controllers/resources_controller.rb.erb
|
146
|
+
- lib/generators/web_feed/templates/controllers/news_controller.rb.erb
|
147
|
+
- lib/generators/web_feed/templates/views/layouts/_webfeed.html.erb
|
148
|
+
- lib/generators/web_feed/templates/views/layouts/webfeed.html.erb
|
149
|
+
- lib/generators/web_feed/templates/views/news/show.html.erb
|
150
|
+
- lib/generators/web_feed/templates/views/news/index.html.erb
|
151
|
+
- lib/generators/web_feed/templates/views/keywords/index.html.erb
|
152
|
+
- lib/generators/web_feed/templates/views/keywords/_form.html.erb
|
153
|
+
- lib/generators/web_feed/templates/views/keywords/edit.html.erb
|
154
|
+
- lib/generators/web_feed/templates/views/keywords/new.html.erb
|
155
|
+
- lib/generators/web_feed/templates/views/resources/index.html.erb
|
156
|
+
- lib/generators/web_feed/templates/views/resources/_form.html.erb
|
157
|
+
- lib/generators/web_feed/templates/views/resources/edit.html.erb
|
158
|
+
- lib/generators/web_feed/templates/views/resources/new.html.erb
|
159
|
+
- lib/generators/web_feed/templates/stylesheets/webfeed.css
|
160
|
+
- lib/generators/web_feed/resource_generator.rb
|
161
|
+
- lib/generators/web_feed/news_generator.rb
|
162
|
+
- lib/webfeed.rb
|
163
|
+
- lib/feed_reader.rb
|
164
|
+
- MIT-LICENSE
|
165
|
+
- Rakefile
|
166
|
+
- README.rdoc
|
167
|
+
homepage: https://github.com/tectual/WebFeed
|
168
|
+
licenses: []
|
169
|
+
|
170
|
+
post_install_message:
|
171
|
+
rdoc_options: []
|
172
|
+
|
173
|
+
require_paths:
|
174
|
+
- lib
|
175
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
176
|
+
none: false
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
hash: 3
|
181
|
+
segments:
|
182
|
+
- 0
|
183
|
+
version: "0"
|
184
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - ">="
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
hash: 3
|
190
|
+
segments:
|
191
|
+
- 0
|
192
|
+
version: "0"
|
193
|
+
requirements: []
|
194
|
+
|
195
|
+
rubyforge_project:
|
196
|
+
rubygems_version: 1.8.21
|
197
|
+
signing_key:
|
198
|
+
specification_version: 3
|
199
|
+
summary: Read feeds and republish from your website
|
200
|
+
test_files: []
|
201
|
+
|