Go語言版本的forgery

使用過Python語言的朋友們可能使用過forgery_py,它是一個僞造數據的工具。能僞造一些經常使用的數據。在咱們開發過程和效果展現是十分有用。可是沒有Go語言版本的,因此就動手摺騰吧。python

從源碼入手

在forgery_py的PyPi有一段的實例代碼:git

>>> import forgery_py
>>> forgery_py.address.street_address()
u'4358 Shopko Junction'
>>> forgery_py.basic.hex_color()
'3F0A59'
>>> forgery_py.currency.description()
u'Slovenia Tolars'
>>> forgery_py.date.date()
datetime.date(2012, 7, 27)
>>> forgery_py.internet.email_address()
u'brian@zazio.mil'
>>> forgery_py.lorem_ipsum.title()
u'Pretium nam rhoncus ultrices!'
>>> forgery_py.name.full_name()
u'Mary Peters'
>>> forgery_py.personal.language()
u'Hungarian'

從以上的方法調用咱們能夠看出forgery_py下有一系列的*.py文件,裏面有各類方法,實現各類功能,咱們在來經過分析下Python版本的forgery_py的源碼來看看它的實現原理。github

# ForgeryPy 包的一級目錄
├── dictionaries  # 僞造內容和來源目錄,目錄下存放的都是一些文本文件
├── dictionaries_loader.py # 加載文件腳本
├── forgery       # 主目錄,實現各類數據僞造功能,目錄下存放的都是python文件
├── __init__.py

咱們在來看下forgery目錄下的腳本緩存

$ cat name.py
import random

from ..dictionaries_loader import get_dictionary

__all__ = [
    'first_name', 'last_name', 'full_name', 'male_first_name',
    'female_first_name', 'company_name', 'job_title', 'job_title_suffix',
    'title', 'suffix', 'location', 'industry'
]


def first_name():
    """Random male of female first name."""
    _dict = get_dictionary('male_first_names')
    _dict += get_dictionary('female_first_names')

    return random.choice(_dict).strip()

__all__設置能被調用的方法。
first_name()方法是forgery_py中一個典型僞造數據方法,咱們只要來分析它就能夠知道forgery_py的工做原理了。
這個方法代碼不多,能容易就看出_dict = get_dictionary('male_first_names')_dict += get_dictionary('female_first_names')獲取的數據合併,在最後的return random.choice(_dict).strip()返回隨機的數據。它的重點在於get_dictionary(),因此咱們須要來看它的所在位置dictionaries_loader.py文件。bash

$ cat dictionaries_loader
import random

DICTIONARIES_PATH = abspath(join(dirname(__file__), 'dictionaries'))

dictionaries_cache = {}


def get_dictionary(dict_name):
    """
    Load a dictionary file ``dict_name`` (if it's not cached) and return its
    contents as an array of strings.
    """
    global dictionaries_cache

    if dict_name not in dictionaries_cache:
        try:
            dictionary_file = codecs.open(
                join(DICTIONARIES_PATH, dict_name), 'r', 'utf-8'
            )
        except IOError:
            None
        else:
            dictionaries_cache[dict_name] = dictionary_file.readlines()
            dictionary_file.close()

    return dictionaries_cache[dict_name]

以上就是dictionaries_loader.py文件去掉註釋後的因此要內容。它的主要實現就是:定義一個全局的字典參數dictionaries_cache做爲緩存,而後定義方法get_dictionary()獲取源數據,get_dictionary()中每次forgery目錄底下方法調用時先查看緩存,緩存字典中存在數據就直接輸出,不存在就讀取dictionaries底下的對應文件,並存入緩存。最後是返回數據。
總的來講forgery_py的原理就是:一個方法調用,去讀內存中的緩存,存在就直接返回,不存在就到對應的文本文件中讀取並寫入緩存並返回。返回來的數據再隨機選取輸出結果。app

使用Go語言實現

在瞭解了forgery_py的工做原理以後,咱們就能夠來使用Go語言來實現了。dom

# forgery的基本目錄
$ cat forgery
├── dictionaries # 數據源
│   ├── male_first_names
├── name.go   # 具體功能實現
└── loader.go # 加載數據

根據python版本的咱們也來建立對應的目錄。
實現數據的讀取的緩存:工具

// forgery/loader.go
package forgery

import (
    "os"
    "io"
    "bufio"
    "math/rand"
    "time"
    "strings"
)

// 全局的緩存map
var dictionaries map[string][]string = make(map[string][]string)

// 在獲取數據以後隨機輸出
func random(slice []string) string {
    rand.Seed(time.Now().UnixNano())
    n := rand.Intn(len(slice))
    return strings.TrimSpace(slice[n])
}

// 主要的數據加載方法
func loader(name string) (slice []string, err error) {
    slice, ok := dictionaries[name]
    // 緩存中存在數據,直接返回
    if ok {
        return slice, nil
    }
    // 讀取對應文件
    file, err := os.Open("./dictionaries/" + name)
    if err != nil {
        return slice, err
    }
    defer file.Close()
    rd := bufio.NewReader(file)
    for {
        line, err := rd.ReadString('\n')
        slice = append(slice, line)
        if err != nil || io.EOF == err {
            break
        }
    }
    dictionaries[name] = slice
    return slice, nil
}

// 統一的錯誤處理
func checkErr(err error) (string, error) {
    return "", err
}

實現具體的功能:spa

// forgery/name.go
// Random male of female first name.
func FirstName() (string, error) {
    slice, err := loader("male_first_names")
    checkErr(err)
    slice1, err := loader("female_first_names")
    checkErr(err)
    slice = append(slice, slice1...)
    return random(slice), nil
}

這樣就將python語言版本的forgery_py使用Go來實現了。翻譯

最後

上面只是說起了一些工做原理,具體的源代碼能夠看https://github.com/xingyys/fo...,也十分感謝https://github.com/tomekwojci...,具體的思路和裏面的數據源都是他提供的。本人就是作了一些翻譯的的工做。

相關文章
相關標籤/搜索