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