Ruby有着便捷强大的Gem包管理机制,作为五十年后人类使用最多的编程语言,有必要提前普及一下Ruby Gem的编写制作教程,帮助大家更好的使用Ruby,使用Gem,最好也能让Ruby的Gem库更加丰富,社区能够更加活跃。那么如何从零开始制作和发布自己的Gem呢?一起来动手操作一下。

制作和发布Ruby Gem包一共分如下几个步骤:

  1. 在RubyGems上注册帐号(如果你只想在本地或团队内部使用你的Gem,可以跳过这一步)
  2. 编写和打包Gem(gem build xxx.gemspec)
  3. 测试Gem(mang自mu信者可以跳过这一步)
  4. 发布Gem(gem push xxx)

1. 注册RubyGems帐号

RubyGems.ORG 是一个大型的Gems仓库,你可以现在就加入它,贡献你的Gem。这一步想必无需多说,注册完成之后,你就拥有了属于自己的RubyGems帐号,别人就可以看到你的主页和你发布的Gems。

注册完成之后,你还需要将你的crendentials保存到本地,方便后续直接在命令行使用gem命令。运行

1
curl -u 你的用户名 https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials

2. 编写和打包Gem

编写Gem

我们这次要发布的Gem叫做template_chorder,你也可以改名成任意你想要的名字。首先我们创建一个工程目录,我的目录名叫做GemTemplate,其中包含如下内容:

其中,template.gemspec是项目的描述文件,gem build命令会基于这个文件进行打包。

template.gemspec内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14

Gem::Specification.new do |s|
s.name = 'template_chorder'
s.version = '0.0.0'
s.date = '2019-01-11'
s.summary = "Template!"
s.description = "A simple template gem"
s.authors = ["Chorder"]
s.email = '[email protected]'
s.files = ["lib/template.rb"]
s.homepage = 'https://chorder.net/2019/01/11/rubygemtemplate/'
s.license = 'MIT'
end

其中s.name就是将来这个包发布出去的名字。默认的,我们需要将工程的主代码放在lib目录里面,这是ruby的约定。我们的Gem只包含一个很简单的功能,只需要放置全部代码在一个文件当中即可。

lib/template.rb的代码如下:

1
2
3
4
5
class Template
def self.test
puts "Hello, Ruby!"
end
end

就是这么简单。

打包Gem

在工程的根目录,运行

1
gem build template.gemspec 

工程根目录将会产生一个 template_chorder-0.0.0.gem文件。
就是这么简单。

3. 测试Gem

对于刚刚生成的template_chorder-0.0.0.gem,运行

1
gem install template_chorder-0.0.0.gem

来安装它。

安装好以后,就可以在irb解释器中引入和运行它了。完整的过程如下:

疑问
这里其实是有点疑问的,就是为什么gem的名字叫做template_chorder,而在irb中引入的却是template。确实,如果gem包中的文件取名不严谨的话,可能会与其他包产生冲突。至于如何消除冲突,请君自己先思考下。

卸载Gem包,运行 gem uninstall template_chorder

2. 发布Gem

制作好这样一个不负责任的Gem包以后,就可以厚颜无耻地在RubyGems上发布它。但是为了社区的环境卫生清洁,尽量还是不要发布那些粗制滥造的包,就以此为戒吧。
发布Gem包,运行 gem push template_chorder-0.0.0.gem,如果第1步当中的帐号注册和保存
crendentials文件都没有问题,那么包就可以发布出去了。

本文的包发布在:https://rubygems.org/gems/template_chorder

希望能够对你有所帮助。

又到了一年的末尾,自来南京以后,常常满怀仪式感地做某些事。像是每年一度的登栖霞山,以及每年一度的汤山,不定期去看长江,几年一度的登钟山。

今日又去了汤山。汤山位于南京的东郊,据说此地温泉极妙,蒋介石曾经在此整了个疗养院。如今的汤山,满满的商业气息。每至元旦,南方的天气湿冷,老中青成群结队来此中嬉戏。

此温泉我已经连续踏足过三届,每年都是和不同的人。去年是和大学舍友一起在元旦节当天去的。如今2018已经落幕,个人经验是元旦还是尽量不要去泡汤,元旦泡了汤的我的2018年,干什么黄什么。

这次去汤山,感觉人流量少了很多,上次去的时候,地下车库和地面上停了不少车,小杨生煎的队一直排到了门外,连吃口饭都困难。今天的小杨生煎,店铺里只坐了一半的人。与友笑道,莫非是消费真的降级了?连汤都不泡了吗。其实也有可能是,消费升级了,人们都去了更高大上的地方玩耍,只有我们这些LowB还继续流连这里,乐此不疲。

看到温泉的一处亭子上写着一副对联,下阕是“洗身容易洗心难”。我不太想说话。

年底了,总是有各种各样的新闻出来占据我们的视野。吴小波这两天又出来预测明年的经济。朋友圈各路人才对他褒贬不一,有的赞扬有的鄙视。而我觉得他书写的还算中肯,别的不了解,也不评论。

贸易战是要继续打下去的,本世纪异彩纷呈。昨天看了iPhone XR,居然连个3D touch都不带,老乔走了以后库克真是魅了良心。我作为无产阶级恐怕以后只能站在华为这一边。

明年,就是毕业第三个年头了!看看如今的自己,真的是不太满意啊。生命真的太无可奈何,太短暂了,我们甚至都没有足够的时间去好好感受它。以前总梦想自己在各个领域里牛逼,如今甚至觉得,能在一个领域里做出点成绩就已经很对得起这一辈子了。也许很多时候幸福来源于成就感,而成就在外界看来有大有小,有的人穷尽一生作出了一点客观上看起来很微小的成就,可是只要对于生命而言足够精彩,那就足够了。

就像是新闻里拾荒者攒钱赞助贫困大学生的例子,也许他用尽一生攒下的钱,还不如很多人买过的iPhone加起来的钱多,而他的一生,可能要比大多数拥有iPhone的人要精彩。那种用一辈子时间捡破烂,帮助很多人所获得的幸福和成就感,却是我们买iPhone所体会不到的。那种幸福感,可能就叫做信念吧。

今年,从年初就告诉自己,对自己要求少一点,本命年不宜大动,可还是跳了一次槽,搬了两次家。今年给自己的要求就是,花一年时间停一停,听一听自己内心的声音,搞清楚自己想要什么。搞清楚孰可为,孰不可为。就这样昏昏浑浑混了一年以后,其实多少算是想明白一些了。

跟有的人需要在一次很远的旅行中才想明白很多道理相比,我不同,我穷,所以不需要旅行就能想的很明白。

至于想明白什么,其实就是明白了舍弃,不能又想要熊掌,又想熊不想要你的手掌。

明白了人生短暂,光阴似箭,做自己想要做的事情,自己觉得对的事情,不要浪费时间。

要尽到做人、做儿子、做男人应尽的责任。

今日的汤山一行,沐浴过后,算是给过去的自己一个终结,给未来的自己一个新的开始。

悟已往之不谏,知来者之可追。实迷途其未远,觉今是而昨非。

以后,多读书,多写字,多做学问。做个独立思考的人,做个好人。

向着2019,出发!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM debian
MAINTAINER Chorder
WORKDIR /root/
ADD sources.list /etc/apt/
ADD DVWA-master.zip /root/
ADD start.sh /root/
RUN apt-get update
RUN apt-get install -y mariadb-server mariadb-client php php-mysql php-gd zip net-tools
RUN unzip /root/DVWA-master.zip -d /var/www/
RUN rm -rf /etc/apache2/sites-enabled/000-default.conf
ADD dvwa.conf /etc/apache2/sites-enabled/
RUN cp /var/www/DVWA-master/config/config.inc.php.dist /var/www/DVWA-master/config/config.inc.php
RUN sed -i 's/'root'/dvwa/g' /var/www/DVWA-master/config/config.inc.php
RUN sed -i 's/^allow_url_include.*$/allow_url_include = On/g' /etc/php/7.0/apache2/php.ini
RUN chmod 777 -R /var/www/DVWA-master
RUN chmod +x /root/start.sh
ENTRYPOINT /root/start.sh && bash
EXPOSE 80

完整的项目下载:

DVWA-Docker.tgz

多进程示例:

multiprocess.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def test_proc(name,second)
Process.setproctitle("PROC-#{Process.pid}" )
sleep second
puts "#{name} - #{Process.pid} |G/U:#{Process.euid}/#{Process.gid}|PPID:#{Process.ppid}"
Process.exit
puts "Never going here"
end

puts "Main process start - #{Process.pid}"

10.times do |t|

Process.fork do
test_proc("PROC-#{t}",5+t)
end

end

#Process.exit
Process.waitall
puts "Main process exit - #{Process.pid}"

运行结果:

多线程示例:

multithread.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14

require "thread"

threads=[]
6.times do |t|
threads <<Thread.new do
puts "Thread-#{t} start: Process: #{Process.pid} "
sleep 5
puts "Thread-#{t} Done: Process: #{Process.pid} "
end
end

threads.each{|t|t.join}

运行结果:

关于多线程与多进程的区别此处就不再赘述了。
Python3中已经具备了非常完善的多线程与多进程的相关库,可以非常容易的实现程序多进程与多线程的功能。

示例代码如下:

多线程示例

multithread.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

import os
import time
import threading


def test_proc(name):
print( "Run child process %s(%s)" % (name,os.getpid()) )
time.sleep(10)


class MultiThread( threading.Thread ):

def __init__(self,thread_name):
threading.Thread.__init__(self)
self.thread_name = thread_name

def run(self):
test_proc("test")


threads = []
for i in range(1,10):
thread = MultiThread( "Thread-%s" % i )
thread.start()
threads.append( thread )

for t in threads:
t.join()


运行结果:

多进程示例

multiprocess.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

import os
import time
import multiprocessing


def test_proc(name):
print( "Run child process %s(%s)" % (name,os.getpid()) )
time.sleep(10)

if __name__=="__main__":
print("Process start %s" % os.getpid())

processes = []

for i in range( 0, 10):
p=multiprocessing.Process( target=test_proc, args=("Process-%s" % i,) )
p.start()
processes.append(p)


for p in processes:
p.join()

print( "Main process end.")


运行结果:

VirtualBox虚拟机动态分配的虚拟磁盘用久了以后会变得非常大,相当占用空间。可以采用将磁盘闲置空间重新清零的方法,还原多余的占用空间。

虚拟机中操作

第一步是采用zerofree(Linux)或SDelete(Windows)工具在虚拟机中将磁盘空闲区域清零:

Linux

在Linux虚拟机中,先安装zerofree,以Debian为例,执行 apt-get install zerofree 命令安装。

安装完成后,需要重启虚拟机机器进入Recovery模式,操作过程如下。

开机时进入Advanced options:

在Advanced模式中选择recovery mode:

在Recovery模式下登录后,依次执行以下命令清除/dev/sda1设备的闲置空间:

1
2
3
busybox mount -o ro,remount /dev/sda1
zerofree /dev/sda1
busybox mount -o rw,remount /dev/sda1

其他磁盘设备同理。

Windows

如果是Windows虚拟机,可以在https://docs.microsoft.com/zh-cn/sysinternals/downloads/sdelete 下载微软官方的SDelete工具。

下载后解压并且进入SDelete目录,在CMD中运行SDelete.exe,并提供参数,例如清理C盘,则运行以下命令:

1
SDelete.exe -z C:

主机中操作

等待上述过程执行完成以后,可以进入第二步,在主机中回收虚拟磁盘闲置的空间:

进入Virtualbox的虚拟机目录,这里以一台Debian虚拟机为例,在目录中运行以下命令:

1
"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" modifyhd Debian.vdi --compact

C:\Program Files\Oracle\VirtualBox\是Virtualbox在Windows 64位系统中的默认安装位置,如果安装位置与此不同,修改即可。

等待执行到100%,即可完成磁盘回收。

磁盘回收的过程中有效数据不会丢失,可以放心操作。

使用aapt工具获取apk的信息,可以使用

1
aapt dump badging xxx.apk

如果没有aapt,使用apt安装:

1
apt-get install aapt

写个脚本批量获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/bash 

target=$1
if [ -d $target ]
then
for apk in `ls $target/*.apk`
do
app_name=`aapt dump badging $apk | grep 'application: label' | awk -F "'" '{print $2}'`
echo $apk $app_name
done
elif [ ${target#*.} == "apk" ]
then
app_name=`aapt dump badging $target | grep 'application: label' | awk -F "'" '{print $2}'`
echo $target $app_name
else
echo $target "nOt aN aPk fiLe"
fi

脚本下载链接:

get_apk_name

前言

随着技术的发展,近年很多的网站、移动应用程序、微信小程序等等,采用前后端分离、使用JSON API数据传递这种方式来设计和开发。如此,前端程序可以保持独立、并且相对来说比较完整,后端程序逻辑复杂、性能强劲。前端可以有丰富的对数据的展现方式(图表、动画等等),后端也只需要完善相应的对模型的控制,同时输出一份前端所需要的数据,采用Ajax+JSON方式传递,从而让前后端的开发相对而言都更为轻松,在结构合理、技术完备的情况下,工程层面也能实现较大程度的规模上的突破。

Rails作为一种流行的MVC框架,本身在API的开发上已经有了很成熟的配套设施了。Rails的模板支持.json.jbuilder形式的JSON数据渲染,配合jbuilder从模型对象数组直接创建JSON数据,在开发上有着无与伦比的便利。在此之前,如果使用php开发程序,从数组创建JSON,需要先整理好数组,再json_encode(Array)进行输出,很是麻烦。当然身为PHP程序员的你可能要说,PHP也有很强大的API构建框架,可以很方便的构建出健壮的API,是的,我承认有这些框架的存在,只是限于本人的水平和喜好,在PHP开发方面并没有走的那么深远,也就不熟悉其中的一些高级操作了。如果有兴趣,也可以发邮件就这方面进行一些探讨。

近期由于一个项目的需要,需要从已有的Rails应用中开辟出一个新的独立接口,供客户端程序调用,因此学习了一下Rails API的构建方法,也顺便留下此文,作为记录。关于Rails API的构建,我参考了这篇文章 https://blog.csdn.net/li_001/article/details/65937664

以下就是如何使用Rails构建JSON API

我当前采用的环境是 Ruby 2.4.1 + Rails 5.2.0

配置控制器

首先假设我们的应用已经创建好了,并且建立一个Article模型,包含两个字段,title和content,运行迁移并创建种子数据。

此时进入项目根目录,新建一个控制器:

1
rails g controller api/v1/base --no-assets

这个控制器的代码就会位于app/controllers/api/v1/base_controller.rb,我们需要在其中完善一些权限有关的配置。

由于Rails默认的安全属性,以及我们如果之前自定义了一些控制器中的过滤方法,我们需要在该控制器中跳过它,例如我们首先禁用rails自带的CSRF 保护和CSRF token的输出,以及去除掉返回包中的set-cookies头,由于我的应用还使用了devise作为用户认证的模块,所以还要在此禁用掉authenticate_user方法。
完整的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Api::V1::BaseController < ApplicationController
# disable the CSRF token
protect_from_forgery with: :null_session

# disable cookies (no set-cookies header in response)
before_action :destroy_session

# disable the CSRF token
skip_before_action :verify_authenticity_token

# skip devise user authentication
skip_before_action :authenticate_user!

def destroy_session
request.session_options[:skip] = true
end
end

创建好base控制器以后,我们需要在这个控制器的基础上派生出一些新的控制器,这里我们新建一个articles控制器

1
rails g controller api/v1/articles --no-assets

此时除了会生成控制器代码以外,还会在app/views/api/v1目录下创建articles目录,作为模板存放的目录。

articles控制器的代码位于app/controllers/api/v1/users_controller.rb,内容如下

先在其中定义一个show方法:

1
2
3
4
5
6
class Api::V1::ArticlesController < Api::V1::BaseController
def show
@article = Article.find(params[:id])
end
end

配置路由

接下来我们对路由config/routes.rb进行配置

1
2
3
4
5
namespace :api do
namespace :v1 do
resources :articles
end
end

配置视图

articles控制器的视图代码位于app/views/api/v1/articles/,我们在其中建立show.json.jbuilder文件,内容如下:

1
2
3
json.article do
json.(@article, :id, :title, :content)
end

上面这段代码,是jbuilder建立json的语句代码,至于jbuilder的用法,可以参考这篇文章http://ohcoder.com/blog/2015/04/19/jbuilder/

访问接口

启动Rails程序,访问/api/v1/articles/1.json,即可看到接口输出的JSON数据。

接口通信

除了从接口获取JSON数据以外,我们还需要向接口POST JSON数据,并希望接口实现数据的解析和保存。
首先像往常一样,需要在控制器中创建create方法,用于新建数据:

1
2
3
def create
@host = Host.create(article_params)
end

呵呵,一行代码,是的,就这么简单。
而article_params,则是个私有方法,大概需要这样实现:

1
2
3
def article_params
params.require(:article).permit(:title, :content)
end

在客户端(或网页中)向该接口发送数据,地址是/api/v1/articles

发送的数据类似下面这样:

1
2
3
4
5
6
{
"article":{
"title":"test",
"content":"a test article from client"
}
}

直接发送这条数据可能会出错,因为在请求的时候需要带上json格式描述

1
2
Content-Type: application/json
Accept: application/json

完整的POST请求,参考下:

1
2
3
4
5
6
7
8
9
10
11
12
POST /api/v1/articles HTTP/1.1
Host: localhost:3000
Content-Type: application/json
Accept: application/json

{
"article":{
"title":"test",
"content":"a test article from client"
}
}

简介

Devise是Rails中一个功能强大、逻辑复杂的用于实现站点用户管理和登录的组件。鉴于Ruby之不重复造轮子的精神思想,Devise是值得去深入研究学习一下的。由于Devise本身的复杂性,这里对搭建的过程做一个记录,也借此分享一下基于Devise实现最基本的站点用户管理和登录的过程。

环境准备

需要在机器上安装Ruby和Rails。
本次编程环境:

  • Debian 9(Kernel 4.9.0-6-amd64)
  • ruby-2.4.1
  • Rails 5.2.0

开始

新建项目

首先新建一个Rails项目TestSite,创建Post scaffold,包含title和body两个字段

1
2
rails new TestSite
rails g scaffold Post title:string body:string

安装Devise

接着在Gemfile中添加devise

1
gem 'devise'

在项目中执行bundle,以及执行devise:install

1
2
bundle
rails generate devise:install

由于我们暂时只在本地测试,因此修改config/environments/development.rb文件,在其中加入mailer配置:

1
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

生成模型

指定Devise将要运行在哪个模型上,这里使用user作为模型,那么运行:

1
rails generate devise User

下一步,就是运行迁移:

1
rails db:migrate

控制器过滤

如果希望在应用运行之前校验用户身份,在ApplicationController中加入以下过滤器:

1
before_action :authenticate_user!

指定路由:

1
root to: 'posts#index'

添加注销功能

在Application的首页,加上用户注销的链接:

1
<%= link_to "Logout", destroy_user_session_path, method: "DELETE"  if current_user %>

配置视图

如果想要自定义登陆界面的视图,则运行以下命令:

1
rails g devise:views users

这里后面带模型名称,就会创建在这个模型范围内的视图(建议这样做,便于以后拓展多重用户身份模型)

此时就可以在相应的视图中自定义登录、注册、重置密码等相应的界面了。

配置控制器

生成控制器就和生成视图的流程是类似的,运行:

1
rails generate devise:controllers users

这样控制器就创建好了。

控制器这一段是值得好好说道说道的。
首先观察下控制器,控制器是可以追加功能的,也可以覆盖原来的方法,不过不推荐这样做,因为从目前经验来看devise自带的控制器已经足够健壮了。但是有时候,我们需要在原有的基础上新增一些功能,例如记录登录日志、增加一点自定义认证方式等等。这里简单介绍下如何在控制器中新增功能。
上一步操作,为我们生成了以下控制器:

1
2
3
4
5
6
app/controllers/users/confirmations_controller.rb
app/controllers/users/passwords_controller.rb
app/controllers/users/registrations_controller.rb
app/controllers/users/sessions_controller.rb
app/controllers/users/unlocks_controller.rb
app/controllers/users/omniauth_callbacks_controller.rb

这里以登录为例,如果我们想要改写登录功能,首先我们要在路由中改写我们要复写的控制器路由:

routes.rb中:

1
2
3
4
5
6
7
8
9
10
11
Rails.application.routes.draw do
#devise_for :users
resources :posts
root to: 'posts#index'

devise_for :users, controllers: {
# 这一行定义了有关sessions的控制选项,交由我们即将复写的sessions控制器处理。
sessions: 'users/sessions'
}

end

接着修改app/controllers/users/sessions_controller.rb,这里我们简单实现一个功能,当用户在前台登陆时,在后台的console中输出用户的登录信息。复写create方法:

1
2
3
4
5
6
7
# POST /resource/sign_in
def create
super
puts "="*64
puts resource.email
puts "="*64
end

尝试在前台登录,控制台输出了我们想要的信息:

待续

上手Markdown,你只需要先熟悉以下几种语法就够了:

  1. 标题、章节
  2. 粗体、斜体
  3. 无序列表、有序列表
  4. 代码、链接、图片
  5. 表格

下面开始一一讲解


1. 标题、章节

标题很简单,用#号就可以。
一级标题是#,二级标题就用##,三级标题就用###,以此类推。
例如以下内容:
# 一级标题
## 二级标题
### 三级标题

在页面中展示的样子就是:

一级标题

二级标题

三级标题

至于章节,一般用—来表示,这样在页面中会显示章节线。
例如:

Area 1

---
Area 2

效果就是:


Area 1


Area 2


2. 粗体、斜体

粗体用**内容**来表示,斜体用*内容*来表示。

例如:

*斜体*

**粗体**

效果:

斜体

粗体


3 . 无序列表、有序列表

列表一般用

+ 无序列表1级
    + 无序列表2级
        + 无序列表3级

1. 有序列表1
2. 有序列表2

来表示

显示的效果如下:

  • 无序列表1级
    • 无序列表2级
      • 无序列表3级
  1. 有序列表1
  2. 有序列表2

4. 代码、链接、图片

  • 代码
    大段的代码,以tab开头就可以。或是用三个`来表示。小段的代码,用两个反引号来表示。例如:
1
2
3
4
5
6

\`\`\`ruby
#test code
puts "hello"
\`\`\`
#去掉\

显示的效果就是:

1
2
#test code
puts "hello"
  • 链接和图片

这个稍微复杂点,链接用:

[链接描述](URL)

图片用

![图片描述](URL)

例如:

[百度](https://www.baidu.com/)

![百度Logo](https://www.baidu.com/favicon.ico)

效果:

百度

百度Logo


5. 表格

表格一般是以下形式:

|表格|表格|表格|表格|表格|
|:-|:-|:-|:-|:-|
|1|2|3|4|5
|6|7|8|9|0

效果:

表格 表格 表格 表格 表格
1 2 3 4 5
6 7 8 9 0
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×