首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >生成随机“人物”的Ruby脚本

生成随机“人物”的Ruby脚本
EN

Code Review用户
提问于 2018-07-17 01:24:59
回答 1查看 200关注 0票数 3

我正在开发一个小型Ruby程序,为Neo4J数据库生成随机数据,包括人员、地址、电话号码等。

我完全是Ruby的初学者,所以我想在这里张贴我的进展,以得到审查。我刚刚完成了“人员”生成功能。

EntityFaker.rb

代码语言:javascript
复制
=begin
    EntityFaker.rb
=end

require_relative "EntityFactory"

class Main

    public
    def self.generate_entities
        puts "Generating entities..."
        EntityFactory.test_function
    end

    generate_entities
end

EntityFactory.rb

代码语言:javascript
复制
=begin
    Entity-Factory
=end

require 'faker'
require 'pp'
require_relative 'Entities/Person'

class EntityFactory

    @@person_array = []

    public
    def self.test_function()
        generate_people(15)
    end

    private
    def self.generate_people(number)
        number.times do |n|

            sex = Faker::Gender.binary_type
            age = rand(18...65)

            person = Person.new(
                rand_bool ? Faker::Name.prefix : nil,
                (sex == 'Male') ? Faker::Name.unique.male_first_name : Faker::Name.unique.female_first_name,
                rand_bool ? Faker::Name.middle_name : nil,
                Faker::Name.unique.last_name,
                rand_bool ? Faker::Name.last_name : nil,
                rand_bool ? Faker::Name.suffix : nil,
                Time.now.to_i - age * 31556900, # dob in seconds since epoch
                Person.random_height(sex),
                Person.random_weight,
                sex,
                rand_bool ? sex : Faker::Gender.type,
                Person.random_blood_type,
                Faker::Color.color_name,
                Faker::Color.color_name,
                age,
                Person.random_complexion,
                Person.random_build,
                Faker::Demographic.race
            )

            @@person_array.push(person)
        end

       pp @@person_array
    end

    private
    def self.rand_bool
        [true, false].sample
    end
end

Person.rb

代码语言:javascript
复制
=begin
    Person.rb
=end

class Person

    # http://chartsbin.com/view/38919
    @@min_male_height = 166
    @@max_male_height = 184

    # http://chartsbin.com/view/38920
    @@min_female_height = 147
    @@max_female_height = 170

    # For males and females combined, no data could be found seperating the two.
    # https://en.wikipedia.org/wiki/Human_body_weight#Average_weight_around_the_world
    @@min_weight = 49.591
    @@max_weight = 87.398

    # https://github.com/rubocop-hq/ruby-style-guide/issues/289
    def initialize(
        prefix,
        given_name,
        middle_name,
        family_name,
        maiden_name,
        suffix,
        dob,
        height,
        weight,
        sex,
        gender,
        blood_type,
        eye_colour,
        hair_colour,
        age,
        complexion,
        build,
        race
        )

        @prefix = prefix
        @given_name = given_name
        @middle_name = middle_name
        @family_name = family_name
        @maiden_name = maiden_name
        @suffix = suffix
        create_full_name(prefix, given_name, middle_name, family_name, suffix)
        @dob = dob
        @height = height
        @weight = weight
        @sex = sex
        @gender = gender
        @blood_type = blood_type
        @eye_colour = eye_colour
        @hair_colour = hair_colour
        @age = age
        @complexion = complexion
        @build = build
        @race = race
    end

    private
    def create_full_name(prefix, given_name, middle_name, family_name, suffix)
        @legal_name = @full_name = [prefix, given_name, middle_name, family_name, suffix].compact.join(" ")
    end

    public
    def self.random_weight
        range(@@min_weight, @@max_weight)
    end

    public
    def self.random_height(sex)
        (sex == "Male") ? range(@@min_male_height, @@max_male_height) : range(@@min_female_height, @@max_female_height)
    end

    public
    def self.random_complexion
        # https://www.quora.com/What-are-all-the-different-types-of-skin-tones-or-complexions
        ["Type I", "Type II", "Type III", "Type IV", "Type V", "Type VI"].sample
    end

    public
    def self.random_blood_type
        # https://www.livescience.com/36559-common-blood-type-donation.html
        ["O-positive", "O-negative", "A-positive", "A-negative", "B-positive", "B-negative", "AB-positive", "AB-negative"].sample
    end

    public
    def self.random_build
        # https://www.cityofsacramento.org/-/media/Corporate/Files/Police/Resources/Suspect-Description-Form-SPD.pdf?la=en
        ["Slender", "Medium", "Heavy", "Fat", "Muscular"].sample
    end

    private
    def self.range(min, max)
        (rand * (max - min) + min).round(1)
    end
end
EN

回答 1

Code Review用户

回答已采纳

发布于 2018-07-20 02:56:07

我将主要根据ruby样式和最佳实践来查看您的代码,而不是具体的改进,因为您似乎不熟悉ruby通常的编写方式,并试图将其他语言(特别是它看起来像Java)的想法嵌入ruby语法。这并不是一件坏事,它只是表明你(和我们其他人)仍然在学习。

让我们从语法和更简单的代码样式更改开始,然后我们将深入讨论一些结构更改。

首先,让我们看看您的EntityFaker.rb文件:

我注意到的第一件事是Main类,它似乎是从Java带来的。我们不需要一个主类,我们可以把它放在最外面的范围里,也不需要把它包装在一个方法中。此外,在ruby中,我们通常避免使用=begin=end的块注释,甚至对于多行注释也更喜欢#。因此,我们的EntityFaker.rb文件最终看起来如下所示:

代码语言:javascript
复制
# EntityFaker.rb

require_relative "EntityFactory"

puts "Generating entities..."
EntityFactory.test_function

现在,让我们继续讨论其他两个文件中的一些结构更改。首先,您滥用了类与实例方法的概念,滥用了ruby中的公共/私有方法的概念。类的目的是使它能够被实例化。通过使用def self.name语法声明类方法,可以有效地使其成为保存方法的命名空间,而不是类。此外,当您声明类方法(def self.name)时,它们都是公共的,因此使用公共或私有关键字没有任何效果。这些关键字仅适用于实例方法(def name)。

您还将类用作某种工厂。这不是一堂课应该做的。类应该是生成类实例的模板。您可以构建一个生成类的类,但这不是您在这里要做的。似乎您希望创建一个类并将该类的实例追加到数组中。

您可以使用工厂为类的属性生成随机值,但我认为允许用户随意传递值会更优雅,但如果没有传递值,则可以随机选择。这将让我们将两个文件合并成一个很好的、整洁的类,如下所示:

代码语言:javascript
复制
class Person

    # I've changed all these class variables because 1) class variables
    # are considered bad practice (they have some weird behaviors) and 2)
    # because these numbers are... well... constants.

    # http://chartsbin.com/view/38919
    MIN_MALE_HEIGHT = 166
    MAX_MALE_HEIGHT = 184

    # http://chartsbin.com/view/38920
    MIN_FEMALE_HEIGHT = 147
    MAX_FEMALE_HEIGHT = 170

    # For males and females combined, no data could be found seperating the two.
    # https://en.wikipedia.org/wiki/Human_body_weight#Average_weight_around_the_world
    MIN_WEIGHT = 49.591
    MAX_WEIGHT = 87.398

    # The general gist of what I've done here is I've take the arguments as
    # a hash instead of as a long list, which could become unclear. Taking
    # arguments as a hash lets you create a person like so:
    # Person.new({sex: "Male", age: 64}) which is the same thing as:
    # Person.new(sex: "Male", age: 64) which is the same thing as:
    # Person.new sex: "Male", age: 64 which is much clearer and neater.
    # Also, I've changed it so that any options not passed in the opts hash
    # will be randomly generated.
    #
    # You may be wondering about my usage of "||" (the OR operator). What
    # I'm doing is checking if opts[:whatever] exists. If it does not exist
    # it will return nil, which evaluates to false, and so will move on to
    # to the other side of the operator which will do the random generation.
    # This is a common idiom in ruby.
    def initialize(**opts)
        # Note that I've moved @sex to the top, because it's used in @given_name
        # I've also moved @age, because it's used in a couple other places
        @sex = opts[:sex] || Faker::Gender.binary_type
        @age = opts[:age] || rand(18...65)
        # I've taken the default values of @sex and @age from EntityFactory
        @prefix = opts[:prefix] || rand_bool ? Faker::Name.prefix : nil
        @given_name = opts[:given_name] || (@sex == 'Male') ? Faker::Name.unique.male_first_name : Faker::Name.unique.female_first_name
        @middle_name = opts[:middle_name] || rand_bool ? Faker::Name.middle_name : nil
        @family_name = opts[:family_name] || Faker::Name.unique.last_name
        @maiden_name = opts[:maiden_name] || Faker::Name.unique.last_name
        @suffix = opts[:suffix] || rand_bool ? Faker::Name.suffix : nil
        create_full_name(prefix, given_name, middle_name, family_name, suffix)
        @dob = opts[:dob] || Time.now.to_i - age * 31556900 # dob in seconds since epoch
        @height = opts[:height] || random_height(sex)
        @weight = opts[:weight] || random_weight
        @gender = opts[:gender] || rand_bool ? @sex : Faker::Gender.type
        @blood_type = opts[:blood_type] || random_blood_type
        @eye_colour = opts[:eye_colour] || Faker::Color.color_name
        @hair_colour = opts[:hair_colour] || Faker::Color.color_name
        @complexion = opts[:complexion] || random_complexion
        @build = opts[:build] || random_build
        @race = opts[:race] || Faker::Demographic.race
    end

    private # Note that this private keyword applies to all instance methods below it

    def rand_bool
        [true, false].sample
    end

    def create_full_name(prefix, given_name, middle_name, family_name, suffix)
        @legal_name = @full_name = [prefix, given_name, middle_name, family_name, suffix].compact.join(" ")
    end

    def random_weight
        range(MIN_WEIGHT, MAX_WEIGHT)
    end

    # This could use some restructuring, which I'll go into later
    def random_height(sex)
        (sex == "Male") ? range(MIN_MALE_HEIGHT, MAX_MALE_HEIGHT) : range(MIN_FEMALE_HEIGHT, MAX_FEMALE_HEIGHT)
    end

    def random_complexion
        # https://www.quora.com/What-are-all-the-different-types-of-skin-tones-or-complexions
        ["Type I", "Type II", "Type III", "Type IV", "Type V", "Type VI"].sample
    end

    def random_blood_type
        # https://www.livescience.com/36559-common-blood-type-donation.html
        ["O-positive", "O-negative", "A-positive", "A-negative", "B-positive", "B-negative", "AB-positive", "AB-negative"].sample
    end

    def random_build
        # https://www.cityofsacramento.org/-/media/Corporate/Files/Police/Resources/Suspect-Description-Form-SPD.pdf?la=en
        ["Slender", "Medium", "Heavy", "Fat", "Muscular"].sample
    end

    def range(min, max)
        (rand * (max - min) + min).round(1)
    end
end

最后,要像您设置的那样生成15个人,运行以下命令:

代码语言:javascript
复制
people = (0..15).map do
    Person.new
end

这将使用rubys范围从0到15创建一个数字数组,然后迭代数组并将每个数字更改为一个新的人。

我可能会回到这个答案,并编辑一些更多的想法,但现在我必须要跑。享受吧!

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/199641

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档