<commit_before># key_struct

Defines KeyStruct, which acts the same as ruby's Struct but the struct's
initializer takes keyword args (using a hash, rails-style).  Use it to define
a class via:

    Name = KeyStruct[:first, :last]

or as an anonymous base class for your own enhanced struct:

    class Name < KeyStruct[:first, :last]
      def to_s
        "#{@last}, #{@first}"
      end
    end

Then you can create an instance of the class using keywords for the
parameters:

    name = Name.new(:first => "Jack", :last => "Ripper")

and you have the usal readers and writers

    name.first            # --> "Jack"
    name.last             # --> "Ripper"
    name.last = "Sprat"
    name.last             # --> "Sprat"
    name.to_s             # --> "<NAME>" for the enhanced class example

## Readers, Writers, and Instance Variables

As per above, the normal behavior is to get readers and writers.  But, by
analogy with `attr_reader` vs `attr_accessor`, you can choose whether you want
read/write or just read:

    Writeable = KeyStruct.accesor(:first, :last)      # aliased as KeyStruct[]
    Readonly = KeyStruct.reader(:first, :last)        # class has readers but not writers

The analogy is not just skin deep: `KeyStruct` actually uses `attr_accessor`
or `attr_reader` to define the accessors for the generated class. This means
that you also get the corresponding instance variables:

    name.instance_variable_get("@last") # --> "Sprat"
    name.instance_variable_set("@last", "Sparrow")
    name.last             # --> "Sparrow"

The instance variables can be useful of course when using KeyStruct to define
an anonymous base class for your own classes, as shown for the `to_s` example
above.

(This is one way that `KeyStruct` differs from ruby's built-in `Struct`:
built-in `Struct` does not define instance variables.)

## Default values

If you leave off a keyword when instantiating, normally the member value is
nil:

    name = Name.new(:first => "Jack")
    name.last             # --> nil

But when you define the class you can specify defaults that will be filled in
by the class initializer. For example:

    Name = KeyStruct[:first, :last => "Doe"]

    name = Name.new(:first => "John")
    name.first            # --> "John"
    name.last             # --> "Doe"

    name = Name.new(:first => "John", :last => "Deere")
    name.first            # --> "John"
    name.last             # --> "Deere"

## Argument Checking

The struct initializer checks for invalid arguments:

    name = Name.new(:this_is_a_typo => "Xavier")  # --> raises ArgumentError

## Comparison

KeyStruct classes define the == operator, which returns true iff all
corresponding struct members are equal (likewise via ==)

    Name.new(:first => "John", :last => "Doe") == Name.new(:first => "John", :last => "Doe")    # --> true
    Name.new(:first => "John", :last => "Doe") == Name.new(:first => "Jane", :last => "Doe")    # --> false

As a convenience when a well-defined ordering is needed, KeyStruct classes
defines the <=> operator and includes the `Comparable` module. The <=>
operator applies <=> to the coresponding struct members sequentially,
returning the first that is non-0. The comparison is performed in the order
the keys were listed in the class definition, so the first key is the primary
comparison key, and so on down the line.  Thus:

    Name = KeyStruct[:first, :last]
    Name.new(:first => "Abigail", :last => "Zither") <=> Name.new(:first => "Zenobia", :last => "Aardvark")           # --> -1

    LastFirst = KeyStruct[:last, :first]
    LastFirst.new(:first => "Abigail", :last => "Zither") <=> LastFirst.new(:first => "Zenobia", :last => "Aardvark") # --> +1

## to_s and inspect

KeyStruct classes define reasonable default `to_s` and `inspect` methods,
along the lines of:

    Name.new(:first => "Jack", :last => "Ripper").to_s      # --> '[Name first:Jack last:Ripper]'
    Name.new(:first => "Jack", :last => "Ripper").inspect   # --> '<Name:0x1234abcd first:"Jack" last:"Ripper">'

## Converting to a hash

KeyStruct classes define a `to_hash` method that returns a hash containing all
members and their values:

    Name.new(:first => "Jack", :last => "Ripper").to_hash   # --> {:first => "Jack", :last => "Ripper")

## Introspection

KeyStruct classes let you examine their definition:

    Name = KeyStruct[:first, :last => "Doe"]
    Name.keys       # --> [ :first, :last ]
    Name.defaults   # --> { :last => "Doe" }

## Installation

Install via:

    % gem install key_struct

or in your Gemfile:

    gem "key_struct"

## Versions

Requires ruby >= 1.9.2.  (Has been tested on MRI 1.9.2 and MRI 1.9.3)

## History

Release Notes:

*   0.4.2 - Bug fix: make class introspection work for derived classes. 
    Restore metaprogramming: inheritance too fragile.
*   0.4.1 - Cache anonymous classes to avoid TypeError: superclass mismatch. 
    Nicer strings for anonymous classes.  Internals change: use base class
    rather than metaprogramming.
*   0.4.0 - Introduce class introspection
*   0.3.1 - Bug fix: to_hash when a value is an array.  Was raising
    ArgumentError for Hash
*   0.3.0 - Introduced to_s and inspect
*   0.2.1 - Bug fix: return false for == with an incompatible object.  Was
    raising NoMethodError
*   0.2.0 - Introduced <=> and to_hash
*   0.1.0 - Introduced ==
*   0.0.1 - Initial version


Past: There was some discussion around this idea in this thread:
http://www.ruby-forum.com/topic/138124 in 2008. 

Future: I hope that this gem will be obviated in future versions of ruby.

## Note on Patches/Pull Requests

*   Fork the project.
*   Make your feature addition or bug fix.
*   Add tests for it.  Make sure that the coverage report (generated
    automatically when you run rspec) is at 100%
*   Send me a pull request.


## Copyright

Released under the MIT License.  See LICENSE for details.
<commit_msg>Add a Bitdeli badge to README<commit_after># key_struct

Defines KeyStruct, which acts the same as ruby's Struct but the struct's
initializer takes keyword args (using a hash, rails-style).  Use it to define
a class via:

    Name = KeyStruct[:first, :last]

or as an anonymous base class for your own enhanced struct:

    class Name < KeyStruct[:first, :last]
      def to_s
        "#{@last}, #{@first}"
      end
    end

Then you can create an instance of the class using keywords for the
parameters:

    name = Name.new(:first => "Jack", :last => "Ripper")

and you have the usal readers and writers

    name.first            # --> "Jack"
    name.last             # --> "Ripper"
    name.last = "Sprat"
    name.last             # --> "Sprat"
    name.to_s             # --> "<NAME>" for the enhanced class example

## Readers, Writers, and Instance Variables

As per above, the normal behavior is to get readers and writers.  But, by
analogy with `attr_reader` vs `attr_accessor`, you can choose whether you want
read/write or just read:

    Writeable = KeyStruct.accesor(:first, :last)      # aliased as KeyStruct[]
    Readonly = KeyStruct.reader(:first, :last)        # class has readers but not writers

The analogy is not just skin deep: `KeyStruct` actually uses `attr_accessor`
or `attr_reader` to define the accessors for the generated class. This means
that you also get the corresponding instance variables:

    name.instance_variable_get("@last") # --> "Sprat"
    name.instance_variable_set("@last", "Sparrow")
    name.last             # --> "Sparrow"

The instance variables can be useful of course when using KeyStruct to define
an anonymous base class for your own classes, as shown for the `to_s` example
above.

(This is one way that `KeyStruct` differs from ruby's built-in `Struct`:
built-in `Struct` does not define instance variables.)

## Default values

If you leave off a keyword when instantiating, normally the member value is
nil:

    name = Name.new(:first => "Jack")
    name.last             # --> nil

But when you define the class you can specify defaults that will be filled in
by the class initializer. For example:

    Name = KeyStruct[:first, :last => "Doe"]

    name = Name.new(:first => "John")
    name.first            # --> "John"
    name.last             # --> "Doe"

    name = Name.new(:first => "John", :last => "Deere")
    name.first            # --> "John"
    name.last             # --> "Deere"

## Argument Checking

The struct initializer checks for invalid arguments:

    name = Name.new(:this_is_a_typo => "Xavier")  # --> raises ArgumentError

## Comparison

KeyStruct classes define the == operator, which returns true iff all
corresponding struct members are equal (likewise via ==)

    Name.new(:first => "John", :last => "Doe") == Name.new(:first => "John", :last => "Doe")    # --> true
    Name.new(:first => "John", :last => "Doe") == Name.new(:first => "Jane", :last => "Doe")    # --> false

As a convenience when a well-defined ordering is needed, KeyStruct classes
defines the <=> operator and includes the `Comparable` module. The <=>
operator applies <=> to the coresponding struct members sequentially,
returning the first that is non-0. The comparison is performed in the order
the keys were listed in the class definition, so the first key is the primary
comparison key, and so on down the line.  Thus:

    Name = KeyStruct[:first, :last]
    Name.new(:first => "Abigail", :last => "Zither") <=> Name.new(:first => "Zenobia", :last => "Aardvark")           # --> -1

    LastFirst = KeyStruct[:last, :first]
    LastFirst.new(:first => "Abigail", :last => "Zither") <=> LastFirst.new(:first => "Zenobia", :last => "Aardvark") # --> +1

## to_s and inspect

KeyStruct classes define reasonable default `to_s` and `inspect` methods,
along the lines of:

    Name.new(:first => "Jack", :last => "Ripper").to_s      # --> '[Name first:Jack last:Ripper]'
    Name.new(:first => "Jack", :last => "Ripper").inspect   # --> '<Name:0x1234abcd first:"Jack" last:"Ripper">'

## Converting to a hash

KeyStruct classes define a `to_hash` method that returns a hash containing all
members and their values:

    Name.new(:first => "Jack", :last => "Ripper").to_hash   # --> {:first => "Jack", :last => "Ripper")

## Introspection

KeyStruct classes let you examine their definition:

    Name = KeyStruct[:first, :last => "Doe"]
    Name.keys       # --> [ :first, :last ]
    Name.defaults   # --> { :last => "Doe" }

## Installation

Install via:

    % gem install key_struct

or in your Gemfile:

    gem "key_struct"

## Versions

Requires ruby >= 1.9.2.  (Has been tested on MRI 1.9.2 and MRI 1.9.3)

## History

Release Notes:

*   0.4.2 - Bug fix: make class introspection work for derived classes. 
    Restore metaprogramming: inheritance too fragile.
*   0.4.1 - Cache anonymous classes to avoid TypeError: superclass mismatch. 
    Nicer strings for anonymous classes.  Internals change: use base class
    rather than metaprogramming.
*   0.4.0 - Introduce class introspection
*   0.3.1 - Bug fix: to_hash when a value is an array.  Was raising
    ArgumentError for Hash
*   0.3.0 - Introduced to_s and inspect
*   0.2.1 - Bug fix: return false for == with an incompatible object.  Was
    raising NoMethodError
*   0.2.0 - Introduced <=> and to_hash
*   0.1.0 - Introduced ==
*   0.0.1 - Initial version


Past: There was some discussion around this idea in this thread:
http://www.ruby-forum.com/topic/138124 in 2008. 

Future: I hope that this gem will be obviated in future versions of ruby.

## Note on Patches/Pull Requests

*   Fork the project.
*   Make your feature addition or bug fix.
*   Add tests for it.  Make sure that the coverage report (generated
    automatically when you run rspec) is at 100%
*   Send me a pull request.


## Copyright

Released under the MIT License.  See LICENSE for details.



[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/ronen/key_struct/trend.png)](https://bitdeli.com/free "Bitdeli Badge")

{'fraction_non_alphanumeric': 0.11911148365465214, 'fraction_numerical': 0.009974853310980721, 'mean_word_length': 3.104231166150671, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 131, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, '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': '4272475', 'n_tokens_mistral': 3718, 'n_tokens_neox': 3544, 'n_words': 1391}