<commit_before>= Personhood

When you are tired of coding the same kinds of things for your User model (or any other person-like model) with all its typical +first_name+, +full_name+, and other brouhaha, use the Personhood gem to clean up your code by getting rid of those pesky lines and instead focusing on the lines of code that *truly* set your app apart.

This is a bit of an opinionated library, so the following assumptions are in place (although in the future this can be made more customizable):

== Assumptions

1. Your class is expected to have the following attributes:

* email (string)
* username (string)
* first_name (string)
* middle_name (string)
* last_name (string)
* birthdate (date)
* sex (integer)

2. All attributes listed above are +attr_accessible+ as +:admin+.

3. All but the first two attributes (email/username) listed above are +attr_accessible+ under normal cases.

4. Out of the box, +last_name+ and +first_name+ are required. They, along with +middle_name+ are allowed at most 255 characters.

5. As a +before_save+ callback, whitespaces are stripped from each of +last_name+, +first_name+, and +middle_name+.

6. A record without a +birthdate+ attribute set (or nil) is treated as one whose birthdate is today, hence +age+ would be 0.

== Customizations

Currently the only customization at the API level is with regard to overriding the +#to_param+ instance method. Under normal circumstances you would override this to be used as a URL slug (permalinking with strings instead of ID numerics), but the library goes further to set the return value of +#to_s+ to the value of +#to_param+.

Typically, I would suggest you defining your custom +#to_param+ within your model, but if you need to customize +#to_param+ for your own needs but do not wish to have its value associated with +#to_s+, you can override that method instead.

== Usage

=== Installation

Gemfile:

    gem 'personhood', github: 'caleon/personhood'

Model class file (i.e. +app/models/user.rb+):

    class User
      include Juscribe::Personhood
      # ..
    end

The include statement does not necessarily have to be at the very top of the class definition, but just be aware that upon inclusion, the module also writes a +composed_of+ statement, +validates+ defaults, and the aforementioned +attr_accessible+ rules.

=== API

Once your model is properly set up, these are the methods available to you:

    # Given:
    user = User.new({
        email:        '<EMAIL>',
        username:     'johnDoe'
        first_name:   'john',
        last_name:    'doe',
        middle_name:  'quincy',
        sex:          1,
        birthdate:    Date.new(1970, 1, 1)
      }, as: :admin)

Getting back on track, here are the _basic_ methods:

    user.to_param
    # => "johnDoe"

    user.to_s
    # => "johnDoe"

    user.full_name
    # => "<NAME>"

    user.first_and_last_name
    # => "<NAME>"

    user.email_address
    # => "<NAME> <<EMAIL>>"

    user.sex
    # => "m"

    user.sex(:full)
    # => "male"

    user.male?
    # => true

    user.female?
    # => false

    user.androgynous?
    # => false

    # Indeterminate sex:
    andro = User.new

    andro.sex
    # => "?"

    andro.sex(:full)
    # => "(unknown)"

    andro.androgynous?
    # => true

    user.age
    # returns whatever the age happens to be for someone born on 1990/1/1

    andro.age
    # => 0

The following are available due to the underlying Juscribe::Name method. You are free to interact with the Juscribe::Name class if you'd like, but the intent is to be hidden from your code and interacted only via the Juscribe::Personhood module which gets included in your class.

    user.name
    # => "<NAME>"

    user.name.class
    # => Juscribe::Name

    user.name.to_s
    # => "<NAME>"

    user.name.first
    # => "john"

    user.name.middle
    # => "quincy"

    user.name.middle_initial
    # => "q."

    user.name.last
    # => "doe"

    user.name.full
    # => "<NAME>"

    user.name.complete
    # => "<NAME>"

The other byproduct of using this intermediary class is that it allows usage of +ActiveRecord+'s +composed_of+ statement:

    user = User.create(name: '<NAME>') do |u|
      # ..
      # Assume other required attributes are set here
      # ..
    end

    user.first_name
    # => "Jane"

    user.middle_name
    # => "Zeta"

    user.middle_initial
    # => "Z."

    user.last_name
    # => "Doe"

    name = Juscribe::Name.new('Jane', 'Zeta', 'Doe')
    # or
    name = Juscribe::Name.convert('<NAME>')

    User.where(name: name)
    #     User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`first_name` = 'Jane' AND `users`.`middle_name` = 'Zeta' AND `users`.`last_name` = 'Doe'
    # => [#<User id: ..>]

    # Note: this means all mapped name parts must match exactly:
    name = Juscribe::Name.convert('<NAME>')
    User.where(name: name)
    #     User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`first_name` = 'Jane' AND `users`.`middle_name` IS NULL AND `users`.`last_name` = 'Doe'
    # => []

If you see yourself using Juscribe::Name a lot, you might want to consider aliasing it at the root level with:

    Name = Juscribe::Name

=== Sidenote

Examples above were only using the +:admin+ role for demonstration. Ideally such account-level attributes should undergo more strenuous security checks in your controller. A simple way would be:

    user = User.new(params[:user]) do |u|
      u.email     = params[:user][:email]
      u.username  = params[:user][:username]
    end

Values for +#sex+ are left lowercased because I'd argue capitalization should be handled at the CSS level with something like:

    .user .sex { text-transform: capitalize; }

=== Other modules included as a dependency

==== Juscribe::Name

The usage of this class is demonstrated above and its purpose is for abstraction and integration with +composed_of+.

==== Juscribe::DisplayOptional

This is used in the inner-workings of +Personhood+ to display a default "unknown" string if the actual value is blank.

==== Juscribe::TosAcceptable

This module is included in the gem now, but I'm considering taking it out, as it applies less to the "personhood" of an object but more to its "user-account-ness". For now, you may go on to use it in the following way:

    # within app/models/user.rb
    include Juscribe::TosAcceptable

    # within migration
    add_column :users, :tos_accepted_at, :datetime

    # within your registration form
    <%= form_for User.new do |f| %>
      <%#= .. other form stuff %>

      <%= f.label :tos_accepted do %>
        <%= f.check_box :tos_accepted, value: '1' %>
        I agree to the <%= link_to 'Terms of Use', terms_path %>.
      <% end %>

      <%= f.submit %>
    <% end %>

In the background, there is a faux-attribute-accessor for +:tos_accepted+ which, when asked to write a truthy form value, writes the timestamp when the form was submitted.

Note that by including the Juscribe::TosAcceptable you are also adding the acceptance validation on that field (existing records without that field set will not validate).

== Roadmap

=== rex_validate

If you looked in the source code you will find references to regexp validation commented out. As this gem was lifted from my other projects which typically use the rex_validate gem, I had to take out that aspect of the integration for the time being while I work out a cleaner way to integrate the two.

=== More convenient Query parameters

As in: "User.where(name: '<NAME>')"" instead of instantiating a new object of the Juscribe::Name class.

=== Customizable column names

Shouldn't be hard to do, and the aim is to not do +include Juscribe::Personhood+ and instead do:

    class User < ActiveRecord::Base
      claims_personhood columns: {
                          first_name: :name1,
                          # ..
                          birthdate: :dob
                        },
                        defaults: {
                          birthdate: Date.new(1900, 1, 1),
                          age: nil
                        }
    end

... although it might be simpler to +alias_attribute+ and override the +birthdate+ or +age+ methods in those options.

=== General Direction

While it might occur to some to include as options basic groups of functionality involving things like a person's address or profile information, the initial intent of the Personhood library was to contain just the bare minimum commonalities among typical projects. Furthermore, it should apply to non-user-related classes like +President+, for instance, which contains in its table a listing of all the presidents. In such a case, things like even +email_address+ are irrelevant and should not really apply. More fitting, perhaps, are extensions involving things like a person's biometrics (eye color, height, weight), birthplace or ethnicity.

== Contributing to Personhood

* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
* Fork the project.
* Start a feature/bugfix branch.
* Commit and push until you are happy with your contribution.
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

== Copyright

Copyright (c) 2012 caleon. See LICENSE.txt for
further details.

<commit_msg>Doc change reflecting rubygems registry<commit_after>= Personhood

When you are tired of coding the same kinds of things for your User model (or any other person-like model) with all its typical +first_name+, +full_name+, and other brouhaha, use the Personhood gem to clean up your code by getting rid of those pesky lines and instead focusing on the lines of code that *truly* set your app apart.

This is a bit of an opinionated library, so the following assumptions are in place (although in the future this can be made more customizable):

== Assumptions

1. Your class is expected to have the following attributes:

* email (string)
* username (string)
* first_name (string)
* middle_name (string)
* last_name (string)
* birthdate (date)
* sex (integer)

2. All attributes listed above are +attr_accessible+ as +:admin+.

3. All but the first two attributes (email/username) listed above are +attr_accessible+ under normal cases.

4. Out of the box, +last_name+ and +first_name+ are required. They, along with +middle_name+ are allowed at most 255 characters.

5. As a +before_save+ callback, whitespaces are stripped from each of +last_name+, +first_name+, and +middle_name+.

6. A record without a +birthdate+ attribute set (or nil) is treated as one whose birthdate is today, hence +age+ would be 0.

== Customizations

Currently the only customization at the API level is with regard to overriding the +#to_param+ instance method. Under normal circumstances you would override this to be used as a URL slug (permalinking with strings instead of ID numerics), but the library goes further to set the return value of +#to_s+ to the value of +#to_param+.

Typically, I would suggest you defining your custom +#to_param+ within your model, but if you need to customize +#to_param+ for your own needs but do not wish to have its value associated with +#to_s+, you can override that method instead.

== Usage

=== Installation

Gemfile:

    gem 'personhood'
    # or GitHub latest:
    # gem 'personhood', github: 'caleon/personhood'

Model class file (i.e. +app/models/user.rb+):

    class User
      include Juscribe::Personhood
      # ..
    end

The include statement does not necessarily have to be at the very top of the class definition, but just be aware that upon inclusion, the module also writes a +composed_of+ statement, +validates+ defaults, and the aforementioned +attr_accessible+ rules.

=== API

Once your model is properly set up, these are the methods available to you:

    # Given:
    user = User.new({
        email:        '<EMAIL>',
        username:     'johnDoe'
        first_name:   'john',
        last_name:    'doe',
        middle_name:  'quincy',
        sex:          1,
        birthdate:    Date.new(1970, 1, 1)
      }, as: :admin)

Getting back on track, here are the _basic_ methods:

    user.to_param
    # => "johnDoe"

    user.to_s
    # => "johnDoe"

    user.full_name
    # => "<NAME>"

    user.first_and_last_name
    # => "<NAME>"

    user.email_address
    # => "<NAME> <<EMAIL>>"

    user.sex
    # => "m"

    user.sex(:full)
    # => "male"

    user.male?
    # => true

    user.female?
    # => false

    user.androgynous?
    # => false

    # Indeterminate sex:
    andro = User.new

    andro.sex
    # => "?"

    andro.sex(:full)
    # => "(unknown)"

    andro.androgynous?
    # => true

    user.age
    # returns whatever the age happens to be for someone born on 1990/1/1

    andro.age
    # => 0

The following are available due to the underlying Juscribe::Name method. You are free to interact with the Juscribe::Name class if you'd like, but the intent is to be hidden from your code and interacted only via the Juscribe::Personhood module which gets included in your class.

    user.name
    # => "<NAME>"

    user.name.class
    # => Juscribe::Name

    user.name.to_s
    # => "<NAME>"

    user.name.first
    # => "john"

    user.name.middle
    # => "quincy"

    user.name.middle_initial
    # => "q."

    user.name.last
    # => "doe"

    user.name.full
    # => "<NAME>"

    user.name.complete
    # => "<NAME>"

The other byproduct of using this intermediary class is that it allows usage of +ActiveRecord+'s +composed_of+ statement:

    user = User.create(name: '<NAME>') do |u|
      # ..
      # Assume other required attributes are set here
      # ..
    end

    user.first_name
    # => "Jane"

    user.middle_name
    # => "Zeta"

    user.middle_initial
    # => "Z."

    user.last_name
    # => "Doe"

    name = Juscribe::Name.new('Jane', 'Zeta', 'Doe')
    # or
    name = Juscribe::Name.convert('<NAME>')

    User.where(name: name)
    #     User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`first_name` = 'Jane' AND `users`.`middle_name` = 'Zeta' AND `users`.`last_name` = 'Doe'
    # => [#<User id: ..>]

    # Note: this means all mapped name parts must match exactly:
    name = Juscribe::Name.convert('<NAME>')
    User.where(name: name)
    #     User Load (0.6ms)  SELECT `users`.* FROM `users` WHERE `users`.`first_name` = 'Jane' AND `users`.`middle_name` IS NULL AND `users`.`last_name` = 'Doe'
    # => []

If you see yourself using Juscribe::Name a lot, you might want to consider aliasing it at the root level with:

    Name = Juscribe::Name

=== Sidenote

Examples above were only using the +:admin+ role for demonstration. Ideally such account-level attributes should undergo more strenuous security checks in your controller. A simple way would be:

    user = User.new(params[:user]) do |u|
      u.email     = params[:user][:email]
      u.username  = params[:user][:username]
    end

Values for +#sex+ are left lowercased because I'd argue capitalization should be handled at the CSS level with something like:

    .user .sex { text-transform: capitalize; }

=== Other modules included as a dependency

==== Juscribe::Name

The usage of this class is demonstrated above and its purpose is for abstraction and integration with +composed_of+.

==== Juscribe::DisplayOptional

This is used in the inner-workings of +Personhood+ to display a default "unknown" string if the actual value is blank.

==== Juscribe::TosAcceptable

This module is included in the gem now, but I'm considering taking it out, as it applies less to the "personhood" of an object but more to its "user-account-ness". For now, you may go on to use it in the following way:

    # within app/models/user.rb
    include Juscribe::TosAcceptable

    # within migration
    add_column :users, :tos_accepted_at, :datetime

    # within your registration form
    <%= form_for User.new do |f| %>
      <%#= .. other form stuff %>

      <%= f.label :tos_accepted do %>
        <%= f.check_box :tos_accepted, value: '1' %>
        I agree to the <%= link_to 'Terms of Use', terms_path %>.
      <% end %>

      <%= f.submit %>
    <% end %>

In the background, there is a faux-attribute-accessor for +:tos_accepted+ which, when asked to write a truthy form value, writes the timestamp when the form was submitted.

Note that by including the Juscribe::TosAcceptable you are also adding the acceptance validation on that field (existing records without that field set will not validate).

== Roadmap

=== rex_validate

If you looked in the source code you will find references to regexp validation commented out. As this gem was lifted from my other projects which typically use the rex_validate gem, I had to take out that aspect of the integration for the time being while I work out a cleaner way to integrate the two.

=== More convenient Query parameters

As in: "User.where(name: '<NAME>')"" instead of instantiating a new object of the Juscribe::Name class.

=== Customizable column names

Shouldn't be hard to do, and the aim is to not do +include Juscribe::Personhood+ and instead do:

    class User < ActiveRecord::Base
      claims_personhood columns: {
                          first_name: :name1,
                          # ..
                          birthdate: :dob
                        },
                        defaults: {
                          birthdate: Date.new(1900, 1, 1),
                          age: nil
                        }
    end

... although it might be simpler to +alias_attribute+ and override the +birthdate+ or +age+ methods in those options.

=== General Direction

While it might occur to some to include as options basic groups of functionality involving things like a person's address or profile information, the initial intent of the Personhood library was to contain just the bare minimum commonalities among typical projects. Furthermore, it should apply to non-user-related classes like +President+, for instance, which contains in its table a listing of all the presidents. In such a case, things like even +email_address+ are irrelevant and should not really apply. More fitting, perhaps, are extensions involving things like a person's biometrics (eye color, height, weight), birthplace or ethnicity.

== Contributing to Personhood

* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
* Fork the project.
* Start a feature/bugfix branch.
* Commit and push until you are happy with your contribution.
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.

== Copyright

Copyright (c) 2012 caleon. See LICENSE.txt for
further details.


{'fraction_non_alphanumeric': 0.09156489926315248, 'fraction_numerical': 0.0041222239398155305, 'mean_word_length': 3.0858947368421052, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 107, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5467446', 'n_tokens_mistral': 5748, 'n_tokens_neox': 5424, 'n_words': 2429}