A Brief analysis of forgery in Go language version

  • 2020-06-15 09:17:31
  • OfStack

Those of you who have used Python may have used forgery_py, a tool that forges data. Can falsify 1 some commonly used data. In our development process and effect presentation is 10 points useful. But there is no Go version, so do something about it.

Start with the source code

In forgery_py's PyPi there is one instance code:


>>> 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'

From the above method call we can see forgery_py under 1 series of *.py file, there are a variety of methods, to achieve a variety of functions, we in the Python version of forgery_py source code to see its implementation principle.


# ForgeryPy  The package 1 Level directory 
 ├ ─ ─  dictionaries #  Fake content and source directory, directory is stored in 1 Some text files 
 ├ ─ ─  dictionaries_loader.py #  Load file script 
 ├ ─ ─  forgery    #  Home directory, to achieve a variety of data forgery functions, directory storage is python file 
 ├ ─ ─  __init__.py

Let's look at the script in the forgery directory


$ 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()

___ Sets the method that can be called.

The first_name() method is one of the typical bogus data methods in forgery_py. We only need to analyze it to know how forgery_py works.

This method has very little code and is easy to see _dict = get_dictionary('male_first_names') and _dict += get_dictionary('female_first_names') Get the data merged at the end return random.choice(_dict).strip( ) returns random data. The point is this get_dictionary() , so we need to look at its location in the dictionaries_loader.py file.


$ 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]

This is the es49EN_loader.py file with the comments removed. Its main implementation is: define a global dictionary parameter dictionaries_cache as the cache, and then define the method get_dictionary() to obtain the source data. In get_dictionary(), every time the method under forgery directory is called, the cache will be viewed first. If there is any data in the cache dictionary, the corresponding file under dictionaries will be read and stored in the cache. Finally, return data.

In general, the principle of forgery_py is as follows: 1 method call to read the cache in memory, return it when it exists, and read and write it to the corresponding text file and return it when it does not exist. The returned data is then randomly selected for output.

Using Go language implementation

Now that you know how forgery_py works, you can implement it using the Go language.


# forgery Basic directory of 
$ cat forgery
 ├ ─ ─  dictionaries #  The data source 
 │    ├ ─ ─  male_first_names
 ├ ─ ─  name.go  #  Specific function realization 
 └ ─ ─  loader.go #  Load the data 

According to the python version we also create the corresponding directory.

Caching of data read is implemented:


// forgery/loader.go
package forgery
import (
  "os"
  "io"
  "bufio"
  "math/rand"
  "time"
  "strings"
)
//  Global cache map
var dictionaries map[string][]string = make(map[string][]string)
//  Random output after getting the data 
func random(slice []string) string {
  rand.Seed(time.Now().UnixNano())
  n := rand.Intn(len(slice))
  return strings.TrimSpace(slice[n])
}
//  The main data loading method 
func loader(name string) (slice []string, err error) {
  slice, ok := dictionaries[name]
  //  Data in cache, return directly 
  if ok {
    return slice, nil
  }
  //  Read the corresponding file 
  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
}
//  system 1 Error handling for 
func checkErr(err error) (string, error) {
  return "", err
}

Specific functions:


// 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
}

This enables forgery_py in the python language version to be implemented using Go.

The last

Just mentioned above 1 working principle, specific source code can see https: / / github com/xingyys/fo... , also thank https 10 points: / / github com/tomekwojci... , the specific ideas and data sources are provided by him. I have done some translation work.

conclusion


Related articles: