ruby Ruby方法

Ruby方法

ruby_method.rb
def is_even?(val) #method name ends with `?` return boolean
  val % 2 == 0
end

def add_val(x, y)
  x + y #return at last statement
end

is_even? 2 #no need the `()`
a = add_val(1, 2) #a = 3

ruby Ruby哈希

Ruby哈希

ruby_hash.rb
obj = Hash.new
#or
obj = {
    "old_syntax" => 'value 1',
    :old_syntax_too => "value 2",
    new_syntax: "value 3"
}

obj[:assign_sym] = 123

#get value
obj[:new_syntax] #=> "value 3"

ruby Ruby数组

Ruby数组

ruby_array.rb
lang = ['english', 'vietnamese', 'french', 'japanese'] # = Array.new

lang.length #=> 4
lang.size #=> 4

lang.first #=> "english"
lang.last #=> "japanese"

#adding item
lang.push("chinese")
lang << "chinese"
lang[4] = "chinese"

#select item

res = lang.select do |l|
  l =~ /h/ #search the character 'h' in l
end

res = lang.select { |x| x =~ /h/ } #same as above

res.grep(/h/) #same as above

#=> ["english", "french"]

#delete item
lang.delete('chinese')
lang.delete_at(3)

ruby Ruby字符串

Ruby字符串

ruby_string.rb
s1 = "Hello"
s2 = "World"

s3 = "#{s1} Ruby #{s2}" #=> "Hello Ruby World"
s1.length #=> 5
s1[2] #=> l
s1.split 'e' #=> ["H", "llo"]

s1.downcase #=> "hello"
s1.upcase #=> "HELLO"
'hELLo'.capitalize #=> "Hello"

ruby Ruby范围

Ruby范围

bury_scope.rb
class Scope

#starts with $
$global_scope = "/app" #available anywhere

#starts with @@
@@same_class_scope = 1 #available across class instances

def local_scope
  #local variable starts with lowercase or underscore _
  loval_var = 10 #only available to this method
end

def class_scope
  #class variable starts with @
  @name = 'Ruby' #available to this class
end

def set_scope(num)
  @@same_class_scope = num
end

def print_scope
  puts @@same_class_scope
end

end

s1 = Scope.new
s2 = Scope.new

s1.print_scope #=> 1
s2.set_scope(2) #all instances of Scope class will update scope

s1.print_scope #=> 2
s2.print_scope #=> 2

ruby ActiveJob的规范模式实现

ActiveJob的规范模式实现

specification_pattern.rb
class SpecificationJob < ApplicationJob
  include JobSpecifications

  around_perform do |_, block|
    init_specifications # init a bunch of instance variables to remember status of specifications
    block.call # calls the #perform method of jobs
    run_registered_specifications # Actually run the specs
    if specifications_all_passed? 
      execute_if_specifications_all_passed
    else
      execute_if_any_specification_failed if respond_to?(:execute_if_any_specification_failed)
    end
  end

# So our jobs can be written this way

class LikeArticleJob < SpecificationsJob
  def perform(article)
    @article = article
  end

  def check_specifications
    register_prerequisite_spec IsStillInDb.new(article)
    register_spec Article::NotUnpublishedSpecification.new, article
    register_spec User::NotSoftDeletedSpecification.new, article.author
    register_spec Article::NotTooOld.new(max_date: 2.years.ago), article
  end

  def execute_if_specifications_pass
    LikeService.like(article)
  end
end</code>

# And the specification itself is written somehow like 

class Article
  class NotUnpublishedSpecification < Specification
    def satisfaction_evaluation_for(profile)
      satisfies('Article is not unpublished') do
        article.published?
      end
    end
  end
end

class Specification
  attr_accessor :satisfied_conditions
  attr_accessor :unsatisfied_conditions

  def satisfied_by?(*args)
    satisfaction_evaluation_for(*args)
    satisfied?
  end

  # @Abstract
  # The core of the specification
  # Call this method for each spec that must pass
  def satisfaction_evaluation_for(*)
    raise NotImplementedError, 'Implement specification conditions'
  end

  def nothing_evaluated?
    satisfied_conditions.empty? and
    unsatisfied_conditions.empty?
  end

  def satisfied?
    if nothing_evaluated?
      return RuntimeError, 'Conditions not evaluated !'
    else
      unsatisfied_conditions.empty?
    end
  end

  # satisfies(condition) { block }
  def satisfies(condition)
    if yield == true
      satisfied_conditions << condition
      true
    else
      unsatisfied_conditions << condition
      false
    end
  end

  def satisfied_conditions
    @satisfied_conditions ||= []
  end

  def unsatisfied_conditions
    @unsatisfied_conditions ||= []
  end

  # Print comprehensible log of specification satisfactions
  def to_s
    return super if nothing_evaluated?
    (satisfied_conditions.map do |cond|
      "✓ #{cond}"
    end + unsatisfied_conditions.map do |cond|
      "x #{cond}"
    end).join("\n")
  end
end

ruby 系统测试

home_login_spec.rb
 require "rails_helper"
#
# RSpec.describe "visit app", type: :system do
#
#   # it "allows a user to create a project with tasks" do
#   #   visit new_project_path
#   #   fill_in "Name", with: "Project Runway"
#   #   fill_in "Tasks", with: "Choose Fabric:3\nMake it Work:5"
#   #   click_on("Create Project")
#   #   visit projects_path
#   #   expect(page).to have_content("Project Runway")
#   #   expect(page).to have_content(8)
#   # end
#
#   let(:user) { create(:user, password: "test1234") }
#
#   it 'allows user to sign in' do
#     visit root_path
#     fill_in "Email", with: 'admin@radiobot.com'
#     fill_in "Password", with: 'admin1234'
#     click_on('Log in')
#     assert_selector 'p.notice', text: 'Signed in successfully.'
#
#   end
#
# end

require 'rails_helper'

RSpec.describe "landing page_and_authentication", type: :system do

  let(:user) { create(:user, password: "test1234") }

  def login
    visit root_path
    fill_in "Email", with: user.email
    fill_in "Password", with: user.password
    click_on("Log in")
    assert_selector 'p.notice', text: 'Signed in successfully.'
  end

  context 'valid login' do
    it "allows a user to login and access the landing page" do
      login
      visit root_path
      expect(page).to have_content('Home#index')
    end

    it 'allows the user to logout' do
      login
      click_on("Logout")
      assert_selector 'p.alert', text: 'You need to sign in or sign up before continuing.'
    end
  end

  context 'invalid login' do
    it 'declines invalid email' do
      visit root_path
      fill_in "Email", with: 'foo@bar.com'
      fill_in "Password", with: user.password
      click_on("Log in")
      assert_selector 'p.alert', text: 'Invalid Email or password.'
    end

    it 'declines invalid password' do
      visit root_path
      fill_in "Email", with: user.email
      fill_in "Password", with: 'notvalidpass'
      click_on("Log in")
      assert_selector 'p.alert', text: 'Invalid Email or password.'
    end
  end

  context 'deactivated account' do
    it 'declines non active acount' do
    end
  end

  context 'Edit Account Details' do
    xit 'allows the user to change their email and password' do
      login
      click_on("Edit Account Details")
      fill_in "Email", with: 'someone@somewhere.com'
      fill_in "Password", with: 'newpassword123'
      fill_in "Password confirmation", with: 'newpassword123'
      fill_in "Current password", with: user.password
      click_on("Update")
    end

    xit 'various tests for blank feilds in form', pending: 'write tests here' do
    end
  end
end

ruby 标准集合

Gemfile
gem 'redis'

gem "rack-dev-mark"

gem 'sail'

gem 'logster'

gem "bugsnag", "~> 6.11"

gem "trestle", "~> 0.8.11"

group :development do
  gem 'guard-livereload', '~> 2.5', require: false
end

ruby 添加Google字体

fonts
<%= stylesheet_link_tag 'application',
'https://fonts.googleapis.com/css?family=Open+Sans:400&subset=latin',
 media: 'all', 'data-turbolinks-track' => true %>

ruby Rails中基于游标的伪分区伪代码

Rails中基于游标的伪分区伪代码

cursor_based_pagination.rb
class CursorPaginator
  attr_reader :cursor_keys, :max_items, :limit

  CURSOR_DIRECTIONS = {
    after: :gt,
    before: :lt
  }.freeze

  def initialize(options = {})
    @cursor_keys = options.fetch(:cursor_keys, id: :asc)
    @max_items = options.fetch(:max_items, 50)
    @limit = options.fetch(:limit, 10)
  end

  def cursor_paginate(collection, cursor = nil, options = {})
    options.reverse_merge!(direction: :after limit: limit)
    options[:direction] = options[:direction].to_sym
    options[:limit] = [options[:limit], max_items].min

    relation = collection.recorder(cursor_keys).limit(options[:limit])
    relation = query_comparator(relation, cursor, options[:direction]) if cursor.present?
    relation = relation.reverse_merge if direction[:direction] = :before

    PaginationResult.new(self, collection, options)
  end

  private

  def query_comparator(collection, cursor, direction)
    comparator = collection.arel_table[:id].public_send(direction, cursor)
    collection.where(comparator)
  end

  private

  class PaginationResult
    att_reader :paginator, :collection, :options

    def initialize(paginator, collection, options = {})
      @paginator = paginator
      @collection = collection
      @options = options
    end

    def has_more?
      paginator.cursor_paginate(collection, last_item.id, options)
    end

    def last_item
      collection.last
    end
  end
end