dylanninin / dylanninin.com Goto Github PK
View Code? Open in Web Editor NEWPersonal blog powered by GitHub Services
Home Page: https://dylanninin.com
Personal blog powered by GitHub Services
Home Page: https://dylanninin.com
Concurrency vs Parallelism
Goroutines
Unbuffered Channel
Buffered Channel
Go in Action mindmap
Reference
http://aosabook.org/en/sqlalchemy.html is awesome!
SQLAlchemy Layers
Engine, Connection, ResultProxy API
Schema
ORM
Session Overview
Reference
Definition
iproute2 is a collection of userspace utilities for controlling and monitoring various aspects of networking in the Linux kernel, including routing, network interfaces, tunnels, traffic control, and network-related device drivers.
Here's the main objects of IP suite, issue man ip
to see the full list
IP | Object | Command | Description |
---|---|---|---|
ip | address(addr) |
add/del/show/flush |
IP - IPv4 or IPv6 protocol address management |
ip | addrlabel |
add/del/list/flush |
label configuration for protocol address selection |
ip | link |
set/show |
network device configuration |
ip | maddr |
show/add/del |
multicast address |
ip | monitor |
all |
watch for netlink messages |
ip | mroute |
show |
multicast routing cache entry |
ip | neighbour |
add/del/change/replace/show/flush |
manage ARP or NDISC cache entries |
ip | route |
list/flush/add/del/change/append/replace/monitor |
routing table entry |
ip | rule |
list/add/del/flush |
rule in routing policy database |
ip | tunnel |
add/change/del/show |
tunnel over IP |
Reference
Rack provides a minimal interface between webservers that support Ruby and Ruby frameworks.
Request/Response
A HTTP request is a triplet consisting of a method and resource pair, a set of headers and an optional body while a HTTP response is in triplet consisting of a response code, a set of headers and an optional body.
app = Proc.new {|env|
puts "#{Time.now}, env: #{env}"
# status_code, headers, body
[200, {}, ["Hello. The time is #{Time.now}"]]
}
puts app.call({}) # =>
#2016-08-01 13:59:43 +0800, env: {}
#[200, {}, [Hello. The time is 2016-08-01 13:59:43 +0800]
require 'rack'
puts Rack::Handler.constants # =>
#[CGI, FastCGI, WEBrick, LSWS, SCGI, Thin]
Rack::Handler::WEBrick.run app # =>
#[2016-08-01 14:01:05] INFO WEBrick 1.3.1
#[2016-08-01 14:01:05] INFO ruby 2.3.1 (2016-04-26) [x86_64-darwin15]
#[2016-08-01 14:01:05] INFO WEBrick::HTTPServer#start: pid=71956 port=8080
################################################################################
#
# Terminal request with httpie
#
#http :8080
#HTTP/1.1 200 OK
#Connection: Keep-Alive
#Content-Length: 44
#Date: Mon, 01 Aug 2016 06:01:28 GMT
#Server: WEBrick/1.3.1 (Ruby/2.3.1/2016-04-26)
#
#Hello. The time is 2016-08-01 14:01:28 +0800
################################################################################
################################################################################
#
# Rack formatted log
#
#2016-08-01 14:01:28 +0800,
# env: {
# "GATEWAY_INTERFACE"=>"CGI/1.1",
# "PATH_INFO"=>"/",
# "QUERY_STRING"=>"",
# "REMOTE_ADDR"=>"127.0.0.1",
# "REMOTE_HOST"=>"127.0.0.1",
# "REQUEST_METHOD"=>"GET",
# "REQUEST_URI"=>"http://localhost:8080/",
# "SCRIPT_NAME"=>"",
# "SERVER_NAME"=>"localhost",
# "SERVER_PORT"=>"8080",
# "SERVER_PROTOCOL"=>"HTTP/1.1",
# "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/2.3 #.1/2016-04-26)",
# "HTTP_HOST"=>"localhost:8080",
# "HTTP_ACCEPT_ENCODING"=>"gzip, deflate",
# "HTTP_USER_AGENT"=>"HTTPie/0.9.4",
# "HTTP_CONNECTION"=>"keep-alive",
# "HTTP_ACCEPT"=>"*/*",
# "rack.version"=>[1, #3],
# "rack.input"=>#<StringIO:0x007fede39d7730>,
# "rack#.errors"=>#<IO:<STDERR>>,
# "rack.multithread"=>true,
# "rack#.multiprocess"=>false,
# "rack.run_once"=>false,
# "rack.url_scheme"=>"http",
# "rack.hijack?"=>true,
# "rack#.hijack"=>#<Proc:0x007fede39d75c8@/Users/dylanninin/.rvm/gems/ruby-2.3#.1/gems/rack-2.0.1/lib/rack/handler/webrick.rb:74 (lambda)>,
# "rack#.hijack_io"=>nil,
# "HTTP_VERSION"=>"HTTP/1.1",
# "REQUEST_PATH"=>"/"
# }
#127.0.0.1 - - [01/Aug/2016:14:01:28 CST] "GET / HTTP/1.1" 200 44
References
Excerpts from 《Data Structures and Algorithms Using Python》
Introduction
Data items are represented within a computer as a sequence of binary digits. These sequences can appear very similar but have different meanings since computers can store and manipulate different types of data. For example, the binary sequence01001100110010110101110011011100
could be a string of characters, an integer value, or a real value. To distinguish between the different types of data, the term is often used to refer to a collection of values and the term data type to refer to a given type along with a collection of operations for manipulating values of the given type.
Programming languages commonly provide data types as part of the language itself. These data types, known as primitives, come in two categories: simple and complex. The simple data types consist of values that are in the most basic form and cannot be decomposed into smaller parts. Integer and real types, for example, consist of single numeric values. The complex data types, on the other hand, are constructed of multiple components consisting of simple types or other complex types. In Python, objects, strings, lists, and dictionaries, which can contain multiple values, are all examples of complex types. The primitive types provided by a language may not be sufficient for solving large complex problems. Thus, most languages allow for the construction of additional data types, known as user-defined types since they are defined by the programmer and not the language. Some of these data types can themselves be very complex.
Abstractions
To help manage complex problems and complex data types, computer scientists typically work with abstractions. An abstraction is a mechanism for separating the properties of an object and restricting the focus to those relevant in the current context. The user of the abstraction does not have to understand all of the details in order to utilize the object, but only those relevant to the current task or problem.
Two common types of abstractions encountered in computer science are procedural, or functional, abstraction and data abstraction. Procedural abstraction is the use of a function or method knowing what it does but ignoring how it's accomplished. Consider the mathematical square root function which you have probably used at some point. You know the function will compute the square root of a given number, but do you know how the square root is computed? Does it matter if you know how it is computed, or is simply knowing how to correctly use the function sufficient? Data abstraction is the separation of the properties of a data type (its values and operations) from the implementation of that data type. You have used strings in Python many times. But do you know how they are implemented? That is, do you know how the data is structured internally or how the various operations are implemented?
Typically, abstractions of complex problems occur in layers, with each higher layer adding more abstraction than the previous. Consider the problem of representing integer values on computers and performing arithmetic operations on those values. Figure 1.1 illustrates the common levels of abstractions used with integer arithmetic. At the lowest level is the hardware with little to no abstraction since it includes binary representations of the values and logic circuits for performing the arithmetic. Hardware designers would deal with integer arithmetic at this level and be concerned with its correct implementation. A higher level of abstraction for integer values and arithmetic is provided through assembly language, which involves working with binary values and individual instructions corresponding to the underlying hardware. Compiler writers and assembly language programmers would work with integer arithmetic at this level and must ensure the proper selection of assembly language instructions to compute a given mathematical expression. For example, suppose we wish to compute x = a + b - 5. At the assembly language level, this expression must be split into multiple instructions for loading the values from memory, storing them into registers, and then performing each arithmetic operation separately, as shown in the following pseudopodia:
loadFromMem( R1, 'a' )
loadFromMem( R2, 'b' )
add R0, R1, R2
sub R0, R0, 5
storeToMem( R0, 'x' )
To avoid this level of complexity, high-level programming languages add another layer of abstraction above the assembly language level. This abstraction is provided through a primitive data type for storing integer values and a set of well-defined operations that can be performed on those values. By providing this level of abstraction, programmers can work with variables storing decimal values and specify mathematical expressions in a more familiar notation (x = a + b −5) than is possible with assembly language instructions. Thus, a programmer does not need to know the assembly language instructions required to evaluate a mathematical expression or understand the hardware implementation in order to use integer arithmetic in a computer program.
Figure 1.1. Levels of abstraction used with integer arithmetic.
One problem with the integer arithmetic provided by most high-level languages and in computer hardware is that it works with values of a limited size. On 32-bit architecture computers, for example, signed integer values are limited to the range −231...(231 − 1). What if we need larger values? In this case, we can provide long or "big integers" implemented in software to allow values of unlimited size. This would involve storing the individual digits and implementing functions or methods for performing the various arithmetic operations. The implementation of the operations would use the primitive data types and instructions provided by the high-level language. Software libraries that provide big integer implementations are available for most common programming languages. Python, however, actually provides software-implemented big integers as part of the language itself.
Abstract Data Types
An abstract data type (or ) is a programmer-defined data type that specifies a set of data values and a collection of well-defined operations that can be performed on those values. Abstract data types are defined independent of their implementation, allowing us to focus on the use of the new data type instead of how its implemented. This separation is typically enforced by requiring interaction with the abstract data type through an interface or defined set of operations. This is known as information hiding. By hiding the implementation details and requiring ADTs to be accessed through an interface, we can work with an abstraction and focus on what functionality the ADT provides instead of how that functionality is implemented.
Abstract data types can be viewed like black boxes as illustrated in Figure 1.2. User programs interact with instances of the ADT by invoking one of the several operations defined by its interface. The set of operations can be grouped into four categories:
Figure 1.2. Separating the ADT definition from its implementation.
The implementation of the various operations are hidden inside the black box, the contents of which we do not have to know in order to utilize the ADT. There are several advantages of working with abstract data types and focusing on the what. instead of the how.
Data Structures
Working with abstract data types, which separate the definition from the implementation, is advantageous in solving problems and writing programs. At some point, however, we must provide a concrete implementation in order for the program to execute. ADTs provided in language libraries, like Python, are implemented by the maintainers of the library. When you define and create your own abstract data types, you must eventually provide an implementation. The choices you make in implementing your ADT can affect its functionality and efficiency.
Abstract data types can be simple or complex. A simple ADT is composed of a single or several individually named data fields such as those used to represent a date or rational number. The complex ADTs are composed of a collection of data values such as the Python list or dictionary. Complex abstract data types are implemented using a particular data structure, which is the physical representation of how data is organized and manipulated. Data structures can be characterized by how they store and organize the individual data elements and what operations are available for accessing and manipulating the data.
There are many common data structures, including arrays, linked lists, stacks, queues, and trees, to name a few. All data structures store a collection of values, can be applied to manage the collection. The choice of a particular data structure depends on the ADT and the problem at hand. Some data structures are better suited to particular problems. For example, the queue structure is perfect for implementing a printer queue, while the B-Tree is the better choice for a database index. No matter which data structure we use to implement an ADT, by keeping the implementation separate from the definition, we can use an abstract data type within our program and later change to a different implementation, as needed, without having to modify our existing code.
Reference
The Art Of Scalability: Scalable Web Architecture, Processes, and Organizations for the Modern Enterprise
The AKF Scale Cube
Reference
The Rails
Command
which rails
rails: aliased to _rails_command
which _rails_command
_rails_command () {
if [ -e "bin/rails" ]
then
bin/rails $@
elif [ -e "script/rails" ]
then
ruby script/rails $@
elif [ -e "script/server" ]
then
ruby script/$@
else
command rails $@
fi
}
bin/rails
: base on your rails app's root directory#!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../config/application', __dir__)
require_relative '../config/boot'
require 'rails/commands'
summary in bin/rails
Spring
: is a Rails application preloader. It speeds up development by keeping your application running in the background so you don't need to boot it every time you run a test, rake task or migration.APP_PATH
: set the absolute path of Rails Application.require_relative '../config/boot'
: execute bunder setup, install required gemsENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'rails/commands'
: load rails commands##railties/lib/rails/commands.rb
ARGV << '--help' if ARGV.empty?
aliases = {
"g" => "generate",
"d" => "destroy",
"c" => "console",
"s" => "server",
"db" => "dbconsole",
"r" => "runner",
"t" => "test"
}
command = ARGV.shift
command = aliases[command] || command
require 'rails/commands/commands_tasks'
Rails::CommandsTasks.new(ARGV).run_command!(command)
Commands Tasks
bin/rails: Rails::CommandsTasks.new(ARGV).run_command!(command)
: run specified command. https://github.com/rails/rails/blob/master/railties/lib/rails/commands.rb #railties/lib/rails/commands/commands_tasks.rb#L45
def run_command!(command)
command = parse_command(command)
if COMMAND_WHITELIST.include?(command)
send(command)
else
run_rake_task(command)
end
end
require 'rails/commands/commands_tasks'
: https://github.com/rails/rails/blob/master/railties/lib/rails/commands/commands_tasks.rb # railties/lib/rails/commands/commands_tasks.rb#L81
def server
set_application_directory!
require_command!("server")
Rails::Server.new.tap do |server|
# We need to require application after the server sets environment,
# otherwise the --environment option given to the server won't propagate.
require APP_PATH
Dir.chdir(Rails.application.root)
server.start
end
end
summary in rails server
set_application_directory!
: set application directory, locate config.ru
rack file. #railties/lib/rails/commands/commands_tasks.rb#L148
# Change to the application's path if there is no config.ru file in current directory.
# This allows us to run `rails server` from other directories, but still get
# the main config.ru and properly set the tmp directory.
def set_application_directory!
Dir.chdir(File.expand_path('../../', APP_PATH)) unless File.exist?(File.expand_path("config.ru"))
end
require_command!("server")
: require rails server, inherited from Rack Server. # railties/lib/rails/commands/commands_tasks.rb#L137
def require_command!(command)
require "rails/commands/#{command}"
end
server.start
: start rack server, than the app in running#railties/lib/rails/commands/server.rb#L7
module Rails
class Server < ::Rack::Server
...
#railties/lib/rails/commands/server.rb#L51
def initialize(*)
super
set_environment
end
...
#railties/lib/rails/commands/server.rb#L72
def start
print_boot_information
trap(:INT) { exit }
create_tmp_directories
setup_dev_caching
log_to_stdout if options[:log_stdout]
super
ensure
# The '-h' option calls exit before @options is set.
# If we call 'options' with it unset, we get double help banners.
puts 'Exiting' unless @options && options[:daemonize]
end
Rack Server, #4
lib/rack/server.rb
: the generic Rack Server. https://github.com/rack/rack/blob/master/lib/rack/server.rb # lib/rack/server.rb#L51
def initialize(options = nil)
@ignore_options = []
if options
@use_default_options = false
@options = options
@app = options[:app] if options[:app]
else
argv = defined?(SPEC_ARGV) ? SPEC_ARGV : ARGV
@use_default_options = true
@options = parse_options(argv)
end
end
def options
merged_options = @use_default_options ? default_options.merge(@options) : @options
merged_options.reject { |k, v| @ignore_options.include?(k) }
end
def default_options
environment = ENV['RACK_ENV'] || 'development'
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
{
:environment => environment,
:pid => nil,
:Port => 9292,
:Host => default_host,
:AccessLog => [],
:config => "config.ru"
}
end
def app
@app ||= options[:builder] ? build_app_from_string : build_app_and_options_from_config
end
...
def start &blk
if options[:warn]
$-w = true
end
if includes = options[:include]
$LOAD_PATH.unshift(*includes)
end
if library = options[:require]
require library
end
if options[:debug]
$DEBUG = true
require 'pp'
p options[:server]
pp wrapped_app
pp app
end
check_pid! if options[:pid]
# Touch the wrapped app, so that the config.ru is loaded before
# daemonization (i.e. before chdir, etc).
wrapped_app
daemonize_app if options[:daemonize]
write_pid if options[:pid]
trap(:INT) do
if server.respond_to?(:shutdown)
server.shutdown
else
exit
end
end
server.run wrapped_app, options, &blk
end
def server
@_server ||= Rack::Handler.get(options[:server])
unless @_server
@_server = Rack::Handler.default
# We already speak FastCGI
@ignore_options = [:File, :Port] if @_server.to_s == 'Rack::Handler::FastCGI'
end
@_server
end
...
def build_app(app)
middleware[options[:environment]].reverse_each do |middleware|
middleware = middleware.call(self) if middleware.respond_to?(:call)
next unless middleware
klass, *args = middleware
app = klass.new(app, *args)
end
app
end
def wrapped_app
@wrapped_app ||= build_app app
end
Rack::Handler.default
: get the default rack handler. https://github.com/rack/rack/blob/master/lib/rack/handler.rb#L46 def self.default
# Guess.
if ENV.include?("PHP_FCGI_CHILDREN")
Rack::Handler::FastCGI
elsif ENV.include?(REQUEST_METHOD)
Rack::Handler::CGI
elsif ENV.include?("RACK_HANDLER")
self.get(ENV["RACK_HANDLER"])
else
pick ['puma', 'thin', 'webrick']
end
end
rack/fastcgi.rb
: https://github.com/rack/rack/blob/master/lib/rack/handler/fastcgi.rb ...
def self.run(app, options={})
if options[:File]
STDIN.reopen(UNIXServer.new(options[:File]))
elsif options[:Port]
STDIN.reopen(TCPServer.new(options[:Host], options[:Port]))
end
FCGI.each { |request|
serve request, app
}
end
...
def self.serve(request, app)
env = request.env
env.delete "HTTP_CONTENT_LENGTH"
env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
rack_input = RewindableInput.new(request.in)
env.update(
RACK_VERSION => Rack::VERSION,
RACK_INPUT => rack_input,
RACK_ERRORS => request.err,
RACK_MULTITHREAD => false,
RACK_MULTIPROCESS => true,
RACK_RUNONCE => false,
RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http"
)
env[QUERY_STRING] ||= ""
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
env[REQUEST_PATH] ||= "/"
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
begin
status, headers, body = app.call(env)
begin
send_headers request.out, status, headers
send_body request.out, body
ensure
body.close if body.respond_to? :close
end
ensure
rack_input.close
request.finish
end
end
config.ru
: the rack config file# This file is used by Rack-based servers to start the application.
require_relative 'config/environment'
run Rails.application
config/environment.rb
: load and initialize Rails application
# Load the Rails application.
require_relative 'application'
# Initialize the Rails application.
Rails.application.initialize!
config/application.rb
: the Rails application
require_relative 'boot'
require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
require "rails/test_unit/railtie"
# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)
module MyBackend
class Application < Rails::Application
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Only loads a smaller set of middleware suitable for API only apps.
# Middleware like session, flash, cookies can be added back manually.
# Skip views, helpers and assets when generating a new resource.
config.api_only = true
#config.time_zone = 'Beijing'
# i18n config
config.i18n.load_path += Dir[Rails.root.join('locales', '*.{rb,yml}').to_s]
config.i18n.default_locale = 'zh-CN'
end
end
Rails Application
Rails::Application
: https://github.com/rails/rails/blob/master/railties/lib/rails/application.rb # railties/lib/rails/application.rb#L78
class Application < Engine
autoload :Bootstrap, 'rails/application/bootstrap'
autoload :Configuration, 'rails/application/configuration'
autoload :DefaultMiddlewareStack, 'rails/application/default_middleware_stack'
autoload :Finisher, 'rails/application/finisher'
autoload :Railties, 'rails/engine/railties'
autoload :RoutesReloader, 'rails/application/routes_reloader'
...
# railties/lib/rails/application.rb#L348
# Initialize the application passing the given group. By default, the
# group is :default
def initialize!(group=:default) #:nodoc:
raise "Application has been already initialized." if @initialized
run_initializers(group, self)
@initialized = true
self
end
Rails::Engine
: the Rails Engine. https://github.com/rails/rails/blob/master/railties/lib/rails/engine.rb # railties/lib/rails/engine.rb#L345
class Engine < Railtie
autoload :Configuration, "rails/engine/configuration"
...
Engine#call
: the Rack Interface. https://github.com/rails/rails/blob/master/railties/lib/rails/engine.rb#L519 # railties/lib/rails/engine.rb#L519
# Define the Rack API for this engine.
def call(env)
req = build_request env
app.call req.env
end
Application booting process: https://github.com/rails/rails/blob/master/railties/lib/rails/application.rb#L36
# The application is also responsible for setting up and executing the booting
# process. From the moment you require "config/application.rb" in your app,
# the booting process goes like this:
#
# 1) require "config/boot.rb" to setup load paths
# 2) require railties and engines
# 3) Define Rails.application as "class MyApp::Application < Rails::Application"
# 4) Run config.before_configuration callbacks
# 5) Load config/environments/ENV.rb
# 6) Run config.before_initialize callbacks
# 7) Run Railtie#initializer defined by railties, engines and application.
# One by one, each engine sets up its load paths, routes and runs its config/initializers/* files.
# 8) Custom Railtie#initializers added by railties, engines and applications are executed
# 9) Build the middleware stack and run to_prepare callbacks
# 10) Run config.before_eager_load and eager_load! if eager_load is true
# 11) Run config.after_initialize callbacks
Reference
A simple note
Architecture
In Action
https://gist.github.com/dylanninin/bfc9cfce80a4d8737952440b25d61298
Reference
Nginx architecture
Event-Driven
Reference
开发者自定义数据处理程序
Reference
Simple note
Reference
Fast, Good, Cheap options/model
Project Estimation Methods: http://www.precursive.co.uk/project-estimation-methods/
One more method, Passion Estimation ...
Software Development
The Mythical Man-Month
Reference
notes
Reference
我现在都不推荐新手学习 JavaScript,因为 JS 是一门宿主语言,功能取决于宿主环境。要想学好它,至少必须掌握三套API:标准的 JS API,浏览器 API 和 Node API。每一个都是一大堆内容…… –@ruanyifeng
Some core concepts
http://www.martinfowler.com/articles/mocksArentStubs.html
- Dummy objects are passed around but never actually used. Usually they are just used to fill parameter lists.
- Fake objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).
- Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.
- Mocks are what we are talking about here: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.
Simple note
Reference
66 Specific Ways to Debug Software and Systems. All effective approaches for debugging your applications and systems summarized in a single book.
Reference
Outline
Rails Security
Rspec
Reference
//ruby/object.c
* Document-class: Class
*
* Classes in Ruby are first-class objects---each is an instance of
* class <code>Class</code>.
*
* Typically, you create a new class by using:
*
* class Name
* # some code describing the class behavior
* end
*
* When a new class is created, an object of type Class is initialized and
* assigned to a global constant (<code>Name</code> in this case).
*
*
* Classes, modules, and objects are interrelated. In the diagram
* that follows, the vertical arrows represent inheritance, and the
* parentheses metaclasses. All metaclasses are instances
* of the class `Class'.
*
* Initializes the world of objects and classes.
*
* At first, the function bootstraps the class hierarchy.
* It initializes the most fundamental classes and their metaclasses.
* - \c BasicObject
* - \c Object
* - \c Module
* - \c Class
* After the bootstrap step, the class hierarchy becomes as the following
* diagram.
* +---------+ +-...
* | | |
* BasicObject-----|-->(BasicObject)-------|-...
* ^ | ^ |
* | | | |
* Object---------|----->(Object)---------|-...
* ^ | ^ |
* | | | |
* +-------+ | +--------+ |
* | | | | | |
* | Module-|---------|--->(Module)-|-...
* | ^ | | ^ |
* | | | | | |
* | Class-|---------|---->(Class)-|-...
* | ^ | | ^ |
* | +---+ | +----+
* | |
* obj--->OtherClass---------->(OtherClass)-----------...
*
* Then, the function defines classes, modules and methods as usual.
* \ingroup class
//ruby/object.c
*
* BasicObject is the parent class of all classes in Ruby. It's an explicit
* blank class.
*
* BasicObject can be used for creating object hierarchies independent of
* Ruby's object hierarchy, proxy objects like the Delegator class, or other
* uses where namespace pollution from Ruby's methods and classes must be
* avoided.
*
* To avoid polluting BasicObject for other users an appropriately named
* subclass of BasicObject should be created instead of directly modifying
* BasicObject:
*
* class MyObjectSystem < BasicObject
* end
*
* BasicObject does not include Kernel (for methods like +puts+) and
* BasicObject is outside of the namespace of the standard library so common
* classes will not be found without using a full class path.
*
* A variety of strategies can be used to provide useful portions of the
* standard library to subclasses of BasicObject. A subclass could
* <code>include Kernel</code> to obtain +puts+, +exit+, etc. A custom
* Kernel-like module could be created and included or delegation can be used
* via #method_missing:
*
* class MyObjectSystem < BasicObject
* DELEGATE = [:puts, :p]
*
* def method_missing(name, *args, &block)
* super unless DELEGATE.include? name
* ::Kernel.send(name, *args, &block)
* end
*
* def respond_to_missing?(name, include_private = false)
* DELEGATE.include?(name) or super
* end
* end
*
* Access to classes and modules from the Ruby standard library can be
* obtained in a BasicObject subclass by referencing the desired constant
* from the root like <code>::File</code> or <code>::Enumerator</code>.
* Like #method_missing, #const_missing can be used to delegate constant
* lookup to +Object+:
*
* class MyObjectSystem < BasicObject
* def self.const_missing(name)
* ::Object.const_get(name)
* end
* end
*
//ruby/object.c
* Object is the default root of all Ruby objects. Object inherits from
* BasicObject which allows creating alternate object hierarchies. Methods
* on Object are available to all classes unless explicitly overridden.
*
* Object mixes in the Kernel module, making the built-in kernel functions
* globally accessible. Although the instance methods of Object are defined
* by the Kernel module, we have chosen to document them here for clarity.
*
* When referencing constants in classes inheriting from Object you do not
* need to use the full namespace. For example, referencing +File+ inside
* +YourClass+ will find the top-level File class.
*
* In the descriptions of Object's methods, the parameter <i>symbol</i> refers
* to a symbol, which is either a quoted string or a Symbol (such as
* <code>:name</code>).
*/
//ruby/object.c
*
* The Kernel module is included by class Object, so its methods are
* available in every Ruby object.
*
* The Kernel instance methods are documented in class Object while the
* module methods are documented here. These methods are called without a
* receiver and thus can be called in functional form:
*
* sprintf "%.1f", 1.234 #=> "1.2"
*
*
rb_mKernel = rb_define_module("Kernel");
rb_include_module(rb_cObject, rb_mKernel);
A Module is a collection of methods and constants. The methods in a module may be instance methods or module methods. Instance methods appear as methods in a class when the module is included, module methods do not. Conversely, module methods may be called without creating an encapsulating object, while instance methods may not.
In the descriptions that follow, the parameter sym refers to a symbol, which is either a quoted string or a Symbol (such as :name).
module Mod
include Math
CONST = 1
def meth
# ...
end
end
Mod.class #=> Module
Mod.constants #=> [:CONST, :PI, :E]
Mod.instance_methods #=> [:meth]
//ruby/class.c
void
Init_class_hierarchy(void)
{
rb_cBasicObject = boot_defclass("BasicObject", 0);
rb_cObject = boot_defclass("Object", rb_cBasicObject);
rb_gc_register_mark_object(rb_cObject);
/* resolve class name ASAP for order-independence */
rb_class_name(rb_cObject);
rb_cModule = boot_defclass("Module", rb_cObject);
rb_cClass = boot_defclass("Class", rb_cModule);
rb_const_set(rb_cObject, rb_intern_const("BasicObject"), rb_cBasicObject);
RBASIC_SET_CLASS(rb_cClass, rb_cClass);
RBASIC_SET_CLASS(rb_cModule, rb_cClass);
RBASIC_SET_CLASS(rb_cObject, rb_cClass);
RBASIC_SET_CLASS(rb_cBasicObject, rb_cClass);
}
not a good book for me; better to read through #48
A simple note
Architecture
Cute Tracing Logos -- from dtrace to linux
The Tracing Landscape, Oct 2014 -- from dtrace to linux
Reference
DevOps = Development + QA + Operations
DevOps ≠ Dev + Oops
Simple Mindmap of DevOps hidding some details
The full version
Reference
There are two hard things in computer science:
0. off-by-one errors
- cache invalidation
- naming things
– Phil Karlton
In programming languages, closures (also lexical closures or function closures) are techniques for implementing lexically scoped name binding in languages with first-class functions. Operationally, a closure is a record storing a function[a] together with an environment:[1] a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or reference to which the name was bound when the closure was created.[b] A closure—unlike a plain function—allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.
Closures are used to implement continuation-passing style, and in this manner, hide state. Constructs such as objects and control structures can thus be implemented with closures. In some languages, a closure may occur when a function is defined within another function, and the inner function refers to local variables of the outer function. At run-time, when the outer function executes, a closure is formed, consisting of the inner function’s code and references (the upvalues) to any variables of the outer function required by the closure.
A code block is a set of Ruby statements and expressions between braces or a do/end pair.
invocation do | a1, a2, ... |
end
invocation { | a1, a2, ... | }
block arguments
Blocks argument lists are very similar to method argument lists:
Proc Objects
Ruby’s blocks are chunks of code attached to a method. Blocks are not objects, but they can be converted into objects of class Proc.
Proc.new
, again associating it with a blockObject#lambda
, associating a block with the call.->
syntax.The first two styles of Proc object are identical in use. We’ll call these objects raw procs. The third and fourth styles, generated by lambda and ->, add some functionality to the Proc object, as we’ll see in a minute. We’ll call these objects lambdas.
Here’s the big thing to remember: raw procs are basically designed to work as the bodies of control structures such as loops. Lambdas are intended to act like methods. So, lambdas are stricter when checking the parameters passed to them, and a return in a lambda exits much as it would from a method.
calling a Proc
You call a proc by invoking its methods call
, yield
, or []
.
name.(args...)
. This is mapped internally into name.call(args...)
.Procs, break, and next
Within both raw procs and lambdas, executing next
causes the block to exit back to the caller of the block. The return value is the value (or values) passed to next
, or nil
if no values are passed.
def ten_times
10.times do |i|
if yield(i)
puts "Caller likes #{i}"
end
end
end
ten_times do |number|
next(true) if number ==7
end
# => Caller likes 7
#10
Within a raw proc, a break terminates the method that invoked the block. The return value of the method is any parameters passed to the break.
ten_times do |number|
break(true) if number ==7
end
# =>
# true
Return and Blocks
A return from inside a raw block that’s still in scope acts as a return from that scope. A return from a block whose original context is no longer valid raises an exception (LocalJumpError or ThreadError depending on the context).
def meth1
(1..10).each do |val|
return val
end
end
meth1 # => 1
The following example shows a return failing because the context of its block no longer
exists
def meth2(&b)
b
end
res = meth2 { return }
res.call
# produces:
# from prog.rb:6:in `call'
# from prog.rb:6:in `<main>'
# prog.rb:5:in `block in <main>': unexpected return (LocalJumpError)
And here’s a return failing because the block is created in one thread and called in another:
def meth3
yield
end
t = Thread.new do
meth3 { return }
end
t.join
# produces:
# from prog.rb:2:in `meth3'
# from prog.rb:6:in `block in <main>'
# prog.rb:6:in `block (2 levels) in <main>': unexpected return (LocalJumpError)
This is also true if you create the raw proc using Proc.new.
def meth4
p = Proc.new { return 99 }
p.call
puts "Never get here"
end
meth4 # => 99
A lambda behaves more like a free-standing method body: a return simply returns from the block to the caller of the block:
def meth5
p = lambda { return 99 }
res = p.call
"The block returned #{res}"
end
meth5 # => "The block returned 99"
Because of this, if you use Module#define_method
, you’ll probably want to pass it a proc created using lambda
, not Proc.new
, because return will work as expected in the former and will generate a LocalJumpError
in the latter.
A block is a closure:
def n_times(thing)
lambda {|n| thing * n}
end
p1 = n_times(23)
p1.call(3) # => 69
p1.call(4) # => 92
p2 = n_times("hello ")
p2.call(3) # => "hello hello hello "
The method n_times
returns a Proc
object that references the method’s parameter, thing
. Even though that parameter is out of scope by the time the block is called, the parameter remains accessible to the block. This is called a closure
—variables in the surrounding scope that are referenced in a block remain accessible for the life of that block and the life of any Proc object created from that block.
Here list all the references
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.