ruby webexcursions.rb

webexcursions.rb
#!/usr/bin/ruby
# WebExcursions, a script for gathering new Pinboard links with a certain tag
# and generating Markdown/Jekyll posts when enough are collected.
# Brett Terpstra 2013
#
# -f to force writing out current bookmarks to file regardless of count

%w[fileutils set net/https zlib rexml/document time base64 uri cgi stringio].each do |filename|
  require filename
end
$conf = {}
$conf['debug'] = true
# Pinboard credentials
$conf['user'] = ''
$conf['password'] = ''
# Where to store the database
$conf['db_location'] = File.expand_path("./webexcursions")
# Tag to use for finding bloggable bookmarks
$conf['blog_tag'] = 'blogit'
# How many posts must be gathered before publishing
$conf['min_count'] = 5
# relative location of folder for creating drafts
$conf['drafts_folder'] = 'source/_drafts'
# template for post headers
$conf['post_template'] =<<ENDTEMPLATE
---
title: "Web Excursions for #{Time.now.strftime('%B %d, %Y')}"
layout: post
tags:
- bookmarks
categories:
- Bookmarks
post_class: bookmarks
comments: false
---
ENDTEMPLATE

class Net::HTTP
  alias_method :old_initialize, :initialize
  def initialize(*args)
    old_initialize(*args)
    @ssl_context = OpenSSL::SSL::SSLContext.new
    @ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
  end
end

class Utils
  def debug_msg(message,sticky = true)
    if $conf['debug']
      $stderr.puts message
    end
  end
end

class Pinboard
  attr_accessor :user, :pass, :existing_bookmarks, :new_bookmarks
  def initialize
    # Make storage directory if needed
    FileUtils.mkdir_p($conf['db_location'],:mode => 0755) unless File.exists? $conf['db_location']

    # load existing bookmarks database
    @existing_bookmarks = self.read_bookmarks
  end
  # Store a Marshal dump of a hash
  def store obj = @existing_bookmarks, file_name = $conf['db_location']+'/bookmarks.stash', options={:gzip => false }
    marshal_dump = Marshal.dump(obj)
    file = File.new(file_name,'w')
    file = Zlib::GzipWriter.new(file) unless options[:gzip] == false
    file.write marshal_dump
    file.close
    return obj
  end
  # Load the Marshal dump to a hash
  def load file_name
    begin
      file = Zlib::GzipReader.open(file_name)
    rescue Zlib::GzipFile::Error
      file = File.open(file_name, 'r')
    ensure
      obj = Marshal.load file.read
      file.close
      return obj
    end
  end
  # Set up credentials for Pinboard.in
  def set_auth(user,pass)
    @user = user
    @pass = pass
  end

  def new_bookmarks
     return self.unique_bookmarks
  end

  def existing_bookmarks
    @existing_bookmarks
  end

  # retrieves the XML output from the Pinboard API
  def get_xml(api_call)
    xml = ''
    http = Net::HTTP.new('api.pinboard.in', 443)
    http.use_ssl = true
    http.start do |http|
    	request = Net::HTTP::Get.new(api_call)
    	request.basic_auth @user,@pass
    	response = http.request(request)
    	response.value
    	xml = response.body
    end
    return REXML::Document.new(xml)
  end
  # converts Pinboard API output to an array of URLs
  def bookmarks_to_array(doc)
    bookmarks = []
    doc.elements.each('posts/post') do |ele|
      post = {}
      ele.attributes.each {|key,val|
        post[key] = val;
      }
      bookmarks.push(post)
    end
    return bookmarks
  end
  # compares bookmark array to existing bookmarks to find new urls
  def unique_bookmarks
      xml = self.get_xml("/v1/posts/recent?tag=#{$conf['blog_tag']}&count=100")
      bookmarks = self.bookmarks_to_array(xml)
      unless @existing_bookmarks.nil?
        old_hrefs = @existing_bookmarks.map { |x| x['href'] }
        bookmarks.reject! { |s| old_hrefs.include? s['href'] }
      end
      return bookmarks
  end
  # wrapper for load
  def read_bookmarks
    # if the file exists, read it
    if File.exists? $conf['db_location']+'/bookmarks.stash'
      return self.load $conf['db_location']+'/bookmarks.stash'
    else # new database
      return []
    end
  end

  def read_current_excursion
    # if the file exists, read it
    if File.exists? $conf['db_location']+'/current.stash'
      return self.load $conf['db_location']+'/current.stash'
    else # new database
      return []
    end
  end
end

util = Utils.new
pb = Pinboard.new

pb.set_auth($conf['user'], $conf['password'])

# retrieve recent bookmarks
new_bookmarks = pb.new_bookmarks

# load the current draft stash
current_excursion = pb.read_current_excursion
if new_bookmarks.count > 0 || current_excursion.count > 0
  util.debug_msg("Found #{new_bookmarks.count} unindexed bookmarks.",false)
else
  util.debug_msg("No new bookmarks. Exiting.",false)
  exit
end

# merge new bookmarks into main database
existing_hrefs = current_excursion.map { |x| x['href'] }
new_bookmarks.each {|bookmark|
  pb.existing_bookmarks.push(bookmark)
  unless existing_hrefs.include? bookmark['href']
    current_excursion.push(bookmark)
  end
}

pb.store

# if there are 5 or more bookmarks, create a draft post and clear cache
if current_excursion.length >= $conf['min_count'].to_i || ARGV[0] == '-f'
  output = $conf['post_template']
  current_excursion.each_with_index {|bookmark, i|
    output += "[#{bookmark['description']}](#{bookmark['href']})\n"
    output += ": #{bookmark['extended'].gsub(/\n+/,' ')}\n\n"
  }
  File.open("#{$conf['drafts_folder']}/web-excursions-#{Time.now.strftime('%B-%d-%Y').downcase}.md",'w+') do |f|
    f.puts output
  end
  current_excursion = []
  FileUtils.mv($conf['db_location']+'/current.stash',$conf['db_location']+"/published-#{Time.now.strftime('%Y-%m-%d-%s')}.stash")
else # fewer than five bookmarks, list existing and dump stash
  puts "There are currently #{current_excursion.count} bookmarks collected."
  current_excursion.each_with_index {|bookmark, i|
    puts "#{i.to_s}: #{bookmark['description']}"
  }
  pb.store(current_excursion, $conf['db_location']+'/current.stash', options={:gzip => false })
end



ruby 在n段之后将广告容器注入内容

在n段之后将广告容器注入内容

content_with_ad.rb
module PagesHelper
  def content_with_ad(content, ad_count=3)
    p_count = 0

    new_content = content.gsub(/(<p(>|\s+[^>]*>).*?<\/p>)/) { |p|
      p_count = p_count + 1
      if p_count == ad_count
        p + '<div class="above_fold_ad">Ad</div>'
      else
        p
      end
    }

    new_content.html_safe
  end
end

ruby 环境/ test.rb模板

环境/ test.rb模板

test.rb
Asuitestay::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb.

  # The test environment is used exclusively to run your application's
  # test suite. You never need to work with it otherwise. Remember that
  # your test database is "scratch space" for the test suite and is wiped
  # and recreated between test runs. Don't rely on the data there!
  config.cache_classes = true

  # Do not eager load code on boot. This avoids loading your whole application
  # just for the purpose of running a single test. If you are using a tool that
  # preloads Rails for running tests, you may have to set it to true.
  config.eager_load = false

  # Configure static asset server for tests with Cache-Control for performance.
  config.serve_static_assets  = true
  config.static_cache_control = "public, max-age=3600"

  # Show full error reports and disable caching.
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = false

  # Raise exceptions instead of rendering exception templates.
  config.action_dispatch.show_exceptions = true

  # Disable request forgery protection in test environment.
  config.action_controller.allow_forgery_protection = false

  # Tell Action Mailer not to deliver emails to the real world.
  # The :test delivery method accumulates sent emails in the
  # ActionMailer::Base.deliveries array.
  config.action_mailer.delivery_method = :test

  # Print deprecation notices to the stderr.
  config.active_support.deprecation = :stderr
end

ruby Ejemplo de como subir un attachment a Basecamp desde Ruby

Ejemplo de como subir un attachment a Basecamp desde Ruby

Attachments_Basecamp.rb
require 'rubygems'
require 'json'
require 'net/http'
require 'uri'


#HTTP Request Objects
uri = URI.parse('https://basecamp.com/1823619/api/v1/projects/320356/attachments.json') #ruta de subir attachments en Basecamp
@https = Net::HTTP.new(uri.host,uri.port)
@https.use_ssl = true
req = Net::HTTP::Post.new(uri.path)

#Autenticacion
req.basic_auth 'aherrera@softworks.do', 'mipassword'  #change this for your password

#Archivo que quiero subir
binary_file = File.open('/Users/Amhed/Downloads/Revision 6 Sept/broken line.png', 'rb') {|file| file.read }

#HTTP Headers 
req.add_field('User-Agent', 'Softworks') #Esto es necesario pa que funcione la llamada
req.add_field('Content-Type', 'image/png') #Este es el tipo que lleva
req.add_field('Content-Length', binary_file.length)

#Envio del request
req = create_request_object(@attachments_url, 'image/png', binary_file.length)
req.body = binary_content
res = @https.request(req)

ruby spec.helper.rb模板

spec.helper.rb模板

spec_helper.rb
# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'
require 'factory_girl_rails'
require 'database_cleaner'
require 'pry'
include Warden::Test::Helpers
Warden.test_mode!

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }

# Checks for pending migrations before tests are run.
# If you are not using ActiveRecord, you can remove this line.
ActiveRecord::Migration.check_pending! if defined?(ActiveRecord::Migration)

RSpec.configure do |config|
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false

  # If true, the base class of anonymous controllers will be inferred
  # automatically. This will be the default behavior in future versions of
  # rspec-rails.
  config.infer_base_class_for_anonymous_controllers = false

  # Run specs in random order to surface order dependencies. If you find an
  # order dependency and want to debug it, you can fix the order by providing
  # the seed, which is printed after each run.
  #     --seed 1234
  config.order = "random"

  config.before(:suite) do
    DatabaseCleaner.strategy = :deletion
  end

  config.before(:each) do
    DatabaseCleaner.clean
  end

  config.after(:each) do
    Warden.test_reset!
  end

  #no need for 'FactoryGirl.create :user', just 'create :user'
  config.include FactoryGirl::Syntax::Methods
end

ruby features_helper.rb模板

features_helper.rb模板

features_helper.rb
#spec/features/features_helper.rb

require_relative '../spec_helper'
require 'capybara/rspec'
require 'capybara-screenshot/rspec'
require 'selenium-webdriver'
require 'capybara/poltergeist'

Capybara.javascript_driver = :poltergeist


#selenium only
def confirm_popup
  page.driver.browser.switch_to.alert.accept
end

#warden/devise
def login(user = create(:user))
  login_as(user, scope: :user)
end

def login_admin(admin = create(:admin))
  login_as(admin, scope: :staff_member)
end

ruby 以缩略图的形式获取Streamzoo照片并在您的站点中显示

以缩略图的形式获取Streamzoo照片并在您的站点中显示

streamzoo.rb
$ rails g model StreamzooPhotos url:string

##lib/tasks/streamzoo.rake
require 'hpricot'
require 'open-uri'

namespace :streamzoo do
  
  desc "refresh thumbnails"
  task :update_thumbs => :environment do

    StreamzooPhoto.destroy_all
    doc = Hpricot(open('http://streamzoo.com/user/<username>/uploads'))
    uploads = (doc/"#uploads")
    
    thumbnailrows = uploads.search("div[@class='thumbnailRow']")
    
    thumbnailrows.each do |tr|
      tr.search("div[@class='itempic']").each do |itempic|
        source = itempic.search("a/img").first.attributes['src']
        StreamzooPhoto.create({:source => source})
        puts "#{source} done."
      end unless tr.blank?      
    end unless thumbnailrows.blank?
  end

end

##controllers/application_controller.rb
def get_streamzoo_photos
  @streamzoo_photos = StreamzooPhoto.all
end  							

##views/
- @streamzoo_photos.each do |streamzoo|
	%li
    =link_to image_tag(streamzoo.source, {:class => "grayscale", :height => "90", :alt => ""}), streamzoo.source, {:class => "fancybox"}

ruby accepts_nested_attributes

accepts_nested_attributes

accepts_nested_attributes.rb
class Availability < ActiveRecord::Base
  has_many :availability_periods, dependent: :destroy, inverse_of: :availability
  accepts_nested_attributes_for :availability_periods, allow_destroy: true
  validates_associated  :availability_periods
  validate :must_have_periods

  def must_have_periods
    if availability_periods.empty? or availability_periods.all? {|period| period.marked_for_destruction? }
      errors.add(self.property.name, I18n.t('models.availability.periods_required'))
    end
  end
end

class AvailabilityPeriod < ActiveRecord::Base
  belongs_to :availability, inverse_of: :availability_periods
  validates :date_range, :availability, presence: true
end

ruby 使用多态数据库模型自动创建Active Record关联:http://api.rubyonrails.org/classes/ActiveRecord/Associat

使用多态数据库模型自动创建Active Record关联http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Auto-generated+methods

build_other.rb
class Picture < ActiveRecord::Base
  belongs_to :imageable, :polymorphic => true
  attr_accessible :imageable_id, :imageable_type, :name, :url
end

class Document < ActiveRecord::Base
  has_many :pictures, :as => :imageable
  attr_accessible :title, :content
end

class User < ActiveRecord::Base
  has_many :pictures, :as => :imageable
  attr_accessible :name, :email, :superpower
end

@document = Document.new({ :title => 'New Document', :content => 'Lorem ipsum' })

# download file, save reponse as @photo

@document.build_picture({ :name => 'Kitty', :url => @photo.path })

@document.save

ruby 从内容创建关键字

从内容创建关键字

keywords.rb
# gem install Sanitize
require 'Sanitize'

def generate_keywords(content)
  # strip HTML tags
  content = Sanitize.clean content

  # dump content into array and remove short words
  words = content.scan /[A-Za-z0-9]{3,}/

  #  count occurrences of each word
  words_by_count = {}

  words.each do |word|
    word.downcase!

    if (words_by_count[word].nil?)
      words_by_count[word] = 1
    else
      words_by_count[word] = words_by_count[word] + 1
    end
  end

  # remove common words
  common_words = ["about", "accessibility", "add", "ads", "after", "again", "all", "along", "also", "although", "amazon", "and", "another", "any", "application", "are", "area", "around", "association", "aswell", "available", "back", "based", "basically", "because", "become", "becoming", "been", "before", "began", "begin", "begun", "being", "belong", "both", "broader", "business", "but", "came", "can", "com", "come", "coming", "company", "contact", "contents", "copyright", "copyrighted", "copyrights", "could", "day", "does", "down", "during", "each", "else", "elsewhere", "email", "enough", "etc", "even", "ever", "every", "everyday", "except", "far", "farther", "fascinating", "features", "field", "find", "first", "for", "form", "format", "freeimages", "from", "further", "get", "getting", "gone", "got", "had", "happen", "happened", "happening", "happens", "has", "have", "her", "here", "hers", "high", "him", "his", "home", "how", "however", "href", "http", "including", "information", "into", "its", "just", "last", "left", "let", "like", "likely", "likes", "long", "made", "mail", "make", "many", "mass", "may", "million", "mine", "more", "most", "must", "neither", "net", "new", "news", "next", "non", "none", "not", "now", "nowhere", "off", "one", "online", "only", "other", "otherwise", "our", "ours", "out", "over", "own", "owner", "people", "policy", "post", "president", "press", "privacy", "put", "report", "reserved", "right", "rights", "said", "since", "some", "something", "soon", "states", "still", "such", "technology", "than", "that", "thats", "the", "their", "theirs", "them", "there", "therefore", "these", "they", "this", "those", "though", "three", "through", "throughout", "time", "too", "tried", "try", "trying", "two", "uncommon", "under", "unsubscribe", "updates", "use", "used", "user", "users", "using", "varied", "various", "want", "was", "web", "webdesigns", "well", "went", "were", "what", "whatever", "when", "where", "whether", "which", "while", "who", "whom", "whose", "why", "will", "with", "within", "without", "work", "world", "would", "www", "yeah", "year", "years", "yep", "yes", "you", "your", "yours", "very", "much", "inc", "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "she"]

  common_words.each do |word|
    unless words_by_count[word].nil?
      words_by_count.delete word
    end
  end

  # only return keywords with a count of more than 3 and less than 15
  popular_words = []

  words_by_count.each do |word, count|
    if count >= 3 && count < 15
      popular_words.push word
    end
  end
  return popular_words
end