<commit_before># class2

Easily create class hierarchies that support nested attributes, type conversion, equality, and more.

[![Build Status](https://travis-ci.org/sshaw/class2.svg?branch=master)](https://travis-ci.org/sshaw/class2)

## Usage

```rb
class2 :user => [
         :name, :age,
         :addresses => [
           :city, :state, :zip,
           :country => [ :name, :code ]
         ]
       ]
```

This creates 3 classes: `User`, `Address`, and `Country` with the following attribute accessors:

* `User`: name, age, addresses
* `Address`: city, state, zip, country
* `Country`: name, code


Each of these classes are created with
[several additional methods](#methods).  You can also specify types
(or [namespaces](#namespaces)):

```rb
class2 :user => {
         :name => String,
         :age  => Fixnum,
         :addresses => [
           :city, :state, :zip,  # No explicit types for these
           :country => {
             :name => String,
             :code => String
           }
         ]
       }
```

Attributes without types are treated as is.

After calling either one of the above you can do the following:

```rb
user = User.new(
  :name => "sshaw",
  :age  => 99,
  :addresses => [
    { :city => "LA",
      :country => { :code => "US" } },
    { :city => "NY Sizzle",
      :country => { :code => "US" } },
    { :city => "São José dos Campos",
      :country => { :code => "BR" } }
  ]
)

user.name                  # "sshaw"
user.addresses.size        # 3
user.addresses.first.city  # "LA"
user.to_h                  # {:name => "sshaw", :age => 99, :addresses => [ { ... } ]}

# keys can be strings too
country = Country.new("name" => "America", "code" => "US")
address = Address.new(:city => "Da Bay", :state => "CA", :country => country)
user.addresses << address

User.new(:name => "sshaw") == User.new(:name => "sshaw")  # true
```

`class2` can create classes with typed attributes from example hashes.
This makes it possible to build classes for things like API responses using the API response
itself as the specification:

```rb
# From JSON.parse
# of https://api.github.com/repos/sshaw/selfie_formatter/commits
response = [
  {
    "sha" => "f52f1ed9144e1f73346176ab79a61af78df1b6bd",
    "commit" => {
      "author"=> {
        "name"=>"sshaw",
        "email"=>"<EMAIL>",
        "date"=>"2016-06-30T03:51:00Z"
      }
    },
    "comment_count": 0

    # snip full response
  }
]

class2 :commit => response.first

commit = Commit.new(response.first)
commit.author.name    # "sshaw"
commit.comment_count  # 0
```

### class2 API
3 methods are provided. Pick the one that suites your style and/or requirements:

* `class2`
* `Class2`
* `Class2.new`

They all create classes the same way. They all return `nil`.

#### Naming

`class2` uses
[`String#classify`](http://api.rubyonrails.org/classes/String.html#method-i-classify)
to turn keys into class names: `:foo` will be `Foo`, `:foo_bars` will
be `FooBar`.

Plural keys with an array value are always assumed to be accessors for
a collection and will default to returning an `Array`. `#classify` is
used to derive the class names from the plural attribute names. An
`:addresses` key with an `Array` value will result in a class named
`Address` being created.

Plurality is determined by [`String#pluralize`](http://api.rubyonrails.org/classes/String.html#method-i-pluralize).<commit_msg>Mention CLASS2_NO_EXPORT in docs [ci skip]<commit_after># class2

Easily create class hierarchies that support nested attributes, type conversion, equality, and more.

[![Build Status](https://travis-ci.org/sshaw/class2.svg?branch=master)](https://travis-ci.org/sshaw/class2)

## Usage

```rb
class2 :user => [
         :name, :age,
         :addresses => [
           :city, :state, :zip,
           :country => [ :name, :code ]
         ]
       ]
```

This creates 3 classes: `User`, `Address`, and `Country` with the following attribute accessors:

* `User`: name, age, addresses
* `Address`: city, state, zip, country
* `Country`: name, code


Each of these classes are created with
[several additional methods](#methods).  You can also specify types
(or [namespaces](#namespaces)):

```rb
class2 :user => {
         :name => String,
         :age  => Fixnum,
         :addresses => [
           :city, :state, :zip,  # No explicit types for these
           :country => {
             :name => String,
             :code => String
           }
         ]
       }
```

Attributes without types are treated as is.

After calling either one of the above you can do the following:

```rb
user = User.new(
  :name => "sshaw",
  :age  => 99,
  :addresses => [
    { :city => "LA",
      :country => { :code => "US" } },
    { :city => "NY Sizzle",
      :country => { :code => "US" } },
    { :city => "São José dos Campos",
      :country => { :code => "BR" } }
  ]
)

user.name                  # "sshaw"
user.addresses.size        # 3
user.addresses.first.city  # "LA"
user.to_h                  # {:name => "sshaw", :age => 99, :addresses => [ { ... } ]}

# keys can be strings too
country = Country.new("name" => "America", "code" => "US")
address = Address.new(:city => "Da Bay", :state => "CA", :country => country)
user.addresses << address

User.new(:name => "sshaw") == User.new(:name => "sshaw")  # true
```

`class2` can create classes with typed attributes from example hashes.
This makes it possible to build classes for things like API responses using the API response
itself as the specification:

```rb
# From JSON.parse
# of https://api.github.com/repos/sshaw/selfie_formatter/commits
response = [
  {
    "sha" => "f52f1ed9144e1f73346176ab79a61af78df1b6bd",
    "commit" => {
      "author"=> {
        "name"=>"sshaw",
        "email"=>"<EMAIL>",
        "date"=>"2016-06-30T03:51:00Z"
      }
    },
    "comment_count": 0

    # snip full response
  }
]

class2 :commit => response.first

commit = Commit.new(response.first)
commit.author.name    # "sshaw"
commit.comment_count  # 0
```

### class2 API

The are 3 ways to use class2. Pick the one that suites your style and/or requirements:

* `class2()`
* `Class2()`
* `Class2.new`

They all create classes the same way. They all return `nil`.

To control the creation of the top-level methods, see the
[`CLASS2_NO_EXPORT` environment variable](https://github.com/sshaw/class2/blob/a7ebe022b48db33d532cc483b0e036e4ec7d2e66/lib/class2.rb#L11-L23).

#### Naming

`class2` uses
[`String#classify`](http://api.rubyonrails.org/classes/String.html#method-i-classify)
to turn keys into class names: `:foo` will be `Foo`, `:foo_bars` will
be `FooBar`.

Plural keys with an array value are always assumed to be accessors for
a collection and will default to returning an `Array`. `#classify` is
used to derive the class names from the plural attribute names. An
`:addresses` key with an `Array` value will result in a class named
`Address` being created.

Plurality is determined by [`String#pluralize`](http://api.rubyonrails.org/classes/String.html#method-i-pluralize).
{'fraction_non_alphanumeric': 0.15137288376724997, 'fraction_numerical': 0.021340162185232606, 'mean_word_length': 3.0286532951289398, 'pattern_counts': {'":': 2, '<': 9, '<?xml version=': 0, '>': 83, 'https://': 7, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7402213', 'n_tokens_mistral': 2440, 'n_tokens_neox': 2282, 'n_words': 692}