[ANN] arrayfields-4.1.0

NAME
   arrayfields.rb

URIS
   http://www.codeforpeople.com/lib/ruby/
   http://rubyforge.org/projects/codeforpeople/

SYNOPSIS
     require 'arrayfields'

     a = Arrayfields.new :k, :v, :a, :b

     p a[:k] #=> :v
     p a[:a] #=> :b
     p a.fields #=> [:k, :a]
     p a.values #=> [:v, :b]
     p a #=> [:v, :b]
     p a.to_hash #=> {:k => :v, :a => :b}
     p a.pairs #=> [[:k, :v], [:a, :b]]

     a[:foo] = :bar

     p a[:foo] #=> :bar
     p a.fields #=> [:k, :a, :foo]

AND

     require 'arrayfields'

     fields = 'name', 'age'
     a = [ 'zaphod', 42 ]

     a.fields = fields

     a['name'] #=> 'zaphod'
     a[:name ] #=> 'zaphod'
     a.indices 'name', 'age' #=> [ 'zaphod', 42 ]

DESCRIPTION
   allow keyword access to array instances. arrayfields works by adding only a
   few methods to arrays, namely #fields= and fields, but the #fields= method is
   hooked to extend an array on a per object basis. in otherwords __only__ those
   arrays whose fields are set will have auto-magical keyword access bestowed on
   them - all other arrays remain unaffected. arrays with keyword access require
   much less memory when compared to hashes/objects and yet still provide fast
   lookup and preserve data order.

LIST OF OVERRIDDEN METHODS
   Array#[]
   Array#slice
   Array#[]=
   Array#at
   Array#delete_at
   Array#fill
   Array#values_at
   Array#indices
   Array#indexes
   Array#slice!

LIST OF HASH-LIKE METHODS
   Array#each_with_field
   Array#each_pair
   Array#each_key
   Array#each_value
   Array#fetch
   Array#has_key?
   Array#member?
   Array#key?
   Array#has_value?
   Array#value?
   Array#keys
   Array#store
   Array#values
   Array#to_hash
   Array#to_h
   Array#update
   Array#replace
   Array#invert
   Array#pairs

LIST OF ADDED Array METHODS
   Array#fields=
   Array#fields

LIST OF ADDED Array CLASS METHODS
   Array.fields/Array.struct

SAMPLES

   <========< sample/a.rb >========>

   ~ > cat sample/a.rb

     require 'arrayfields'

···

#
     # the class Array has only a few added method, one is for setting the fields,
     # when the fields are set for an array THIS INSTANCE ONLY will be modified to
     # allow keyword access. other arrays will not be affected!
     #
       a = [0,1,2]
       fields = ['zero', 'one', 'two']
       a.fields = fields # ONLY the Array 'a' is affected!
     #
     # keyword access is now allowed for many methods
     #
       p a['zero'] #=> 0
       p a['one'] #=> 1
       p a['two'] #=> 2
       p a.at('one') #=> 1
       p a.values_at('zero', 'two') #=> [0, 2]
     #
     # assigmnet is allowed
     #
       a['zero'] = 42
       p a['zero'] #=> 0
       a['zero'] = 0
     #
     # assignment to non-fields results in the element being appended and the field
     # being added for future use (also appended)
     #
       p(a.fields.join(',')) #=> "zero, one, two"
       p a['three'] #=> nil
       a['three'] = 3
       p(a.fields.join(',')) #=> "zero, one, two, three"
       p a['three'] #=> 3
     #
     # other detructive methods are also keyword enabled
     #
       a.fill 42, 'zero', len = a.size
       p(a.values_at(a.fields)) #=> [42, 42, 42, 42]
       a.replace [0,1,2,3]

       a.slice! 'two', 2
       p a #=> [0,1]

   ~ > ruby sample/a.rb

     0
     1
     2
     1
     [0, 2]
     42
     "zero,one,two"
     nil
     "zero,one,two,three"
     3
     [42, 42, 42, 42]
     [0, 1]

   <========< sample/b.rb >========>

   ~ > cat sample/b.rb

     require 'arrayfields'
     #
     # the struct class factory method can be used in much the same way as ruby's
     # own struct generators and is useful when the fields for a set of arrays is
     # known apriori
     #
       c = Array.struct :a, :b, :c # class generator
       a = c.new [42, nil, nil]
       a[:c] = 42
       p a #=> [42, nil, 42]
     #
     # of course we can append too
     #
       a[:d] = 42.0
       p a[:d] #=> 42.0
       p a #=> [42, nil, 42, 42.0]

   ~ > ruby sample/b.rb

     [42, nil, 42]
     42.0
     [42, nil, 42, 42.0]

   <========< sample/c.rb >========>

   ~ > cat sample/c.rb

     require 'arrayfields'
     #
     # the Array.fields methods generates an insance with those fields
     #
       a = Array.fields :a, :b, :c
       a[:a] = a[:c] = 42
       p a #=> [42, nil, 42]
       p a.fields #=> [:a, :b, :c]
       p a.values #=> [42, nil, 42]

   ~ > ruby sample/c.rb

     [42, nil, 42]
     [:a, :b, :c]
     [42, nil, 42]

   <========< sample/d.rb >========>

   ~ > cat sample/d.rb

     require 'arrayfields'
     #
     # the Arrayfields.new method is a contruct that takes evenly numbered pairs of
     # arbitrary objects and builds up and fielded array
     #
       a = Arrayfields.new :key, :value, :a, :b
       p a.fields #=> [:key, :a]
       p a.values #=> [:value, :b]
     #
     # you can use a hash - but of course the ordering gets lost in the initial
     # hash creation. aka the order of fields get horked by the unorderedness if
     # the hash iteration. it's okay for some purposed though
     #
       a = Arrayfields.new :key => :value, :a => :b
       p a.fields #=> [:key, :a]
       p a.values #=> [:value, :b]
     #
     # lists of pairs get flattened - the result simply has to be evenly numbered
     #
       a = Arrayfields.new [[:key, :value], [:a, :b]]
       p a.fields #=> [:key, :a]
       p a.values #=> [:value, :b]
       p a.pairs #=> [[:key, :value], [:a, :b]]

   ~ > ruby sample/d.rb

     [:key, :a]
     [:value, :b]
     [:key, :a]
     [:value, :b]
     [:key, :a]
     [:value, :b]
     [[:key, :value], [:a, :b]]

   <========< sample/e.rb >========>

   ~ > cat sample/e.rb

     require 'arrayfields'

     Entry = Array.struct :path, :stat

     entry = Entry[ File.basename(__FILE__), File.stat(__FILE__) ]
     p entry[:path] #=> "e.rb"
     p entry.path #=> "e.rb"

     entry.path = 'foo'
     p entry[:path] #=> "foo"
     p entry.path #=> "foo"

     entry.path 'bar' # getter acts as setter without args
     p entry['path'] #=> "bar"
     p entry.path #=> "bar"

   ~ > ruby sample/e.rb

     "e.rb"
     "foo"
     "bar"

AUTHOR
   ara.t.howard@gmail.com

HISTORY
   4.1.0:
     - improved Array.struct method, see sample/e.rb

enjoy.

a @ http://drawohara.com/
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

      a = [0,1,2]
      fields = ['zero', 'one', 'two']
      a.fields = fields # ONLY the Array 'a' is affected!
    #
    # keyword access is now allowed for many methods
    #
      p a['zero'] #=> 0
      p a['one'] #=> 1
      p a['two'] #=> 2
      p a.at('one') #=> 1
      p a.values_at('zero', 'two') #=> [0, 2]
    #
    # assigmnet is allowed
    #
      a['zero'] = 42
      p a['zero'] #=> 0

Surely, the last line above contains a typo. Shouldn't it be

      p a['zero'] #=> 42

Regards, Morton

···

On Sep 14, 2007, at 8:56 PM, ara.t.howard wrote:

Hi ara (Ara, a, ... which is the best salutation?),

There appears to be an incompatibility between arrayfields and active record dynamic finders.

I've filed a bug report here:

http://rubyforge.org/tracker/index.php?func=detail&aid=14040&group_id=1024&atid=4025

but I'm also posting it here to get a wider audience.

I'm using rails 1.2.3. After loading arrayfields 4.1.0 the active record dynamic finders "find_by_ ..." are broken.

Here's a simple test showing the dynamic finder working, requiring arrayfields, and then the dynamic finder stops working.

$ script/console
Loading development environment.

OtmlFile.find_by_path("../../concord/otrunk-examples/BasicExamples/basic_drawing.otml")

=> #<OtmlFile:0x330ebf4 @attributes={"name"=>"basic_drawing.otml", "id"=>"1", "path"=>"../../concord/otrunk-examples/BasicExamples/basic_drawing.otml"}>

require 'arrayfields'

=> ["PseudoHash", "Arrayfields", "Pseudohash", "Fieldable", "FieldedArray", "ArrayFields", "Fieldedarray"]

OtmlFile.find_by_path("../../concord/otrunk-examples/BasicExamples/basic_drawing.otml")

ArgumentError: <nil> not inject-able
         from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:28:in `initialize'
         from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
         from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
         from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:286:in `fields='
         from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:305:in `dup'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1426:in `replace_bind_variables'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1405:in `sanitize_sql_hash'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1388:in `sanitize_sql'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1163:in `add_conditions!'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1096:in `construct_finder_sql'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:997:in `find_every'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:991:in `find_initial'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1204:in `send'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1204:in `method_missing'
         from /usr/local/lib/ruby/gems/1.8/gems/activesupport-1.4.2/lib/active_support/deprecation.rb:44:in `silence'
         from /usr/local/lib/ruby/gems/1.8/gems/activerecord-1.15.3/lib/active_record/base.rb:1204:in `method_missing'
         from (irb):3>>

therein lies the problem with writing documentation :wink:

if you check most of my new stuff the examples generate the README for exactly the reason that i have fat fingers :wink:

thx.

a @ http://drawohara.com/

···

On Sep 14, 2007, at 9:36 PM, Morton Goldberg wrote:

Surely, the last line above contains a typo. Shouldn't it be

      p a['zero'] #=> 42

Regards, Morton

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Here's a much simpler way to generate the problem without rails.

$ irb
irb(main):001:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> a.dup
=> [1, 2, 3]
irb(main):003:0> require 'arrayfields'
=> true
irb(main):004:0> a.dup
ArgumentError: <nil> not inject-able
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:28:in `initialize'
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:286:in `fields='
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:305:in `dup'
        from (irb):4

···

At 11:41 PM +0900 9/18/07, Stephen Bannasch wrote:

There appears to be an incompatibility between arrayfields and active record dynamic finders.

I've filed a bug report here:

http://rubyforge.org/tracker/index.php?func=detail&aid=14040&group_id=1024&atid=4025

$ script/console
Loading development environment.

OtmlFile.find_by_path("../../concord/otrunk-examples/BasicExamples/basic_drawing.otml")

=> #<OtmlFile:0x330ebf4 @attributes={"name"=>"basic_drawing.otml", "id"=>"1", "path"=>"../../concord/otrunk-examples/BasicExamples/basic_drawing.otml"}>

require 'arrayfields'

=> ["PseudoHash", "Arrayfields", "Pseudohash", "Fieldable", "FieldedArray", "ArrayFields", "Fieldedarray"]

OtmlFile.find_by_path("../../concord/otrunk-examples/BasicExamples/basic_drawing.otml")

thanks.

cfp:~ > rails test --database=sqlite3 > /dev/null 2>&1 && cd test

cfp:~/test > ./script/console
Loading development environment.

>> c = ActiveRecord::Base.connection
=> #<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x345227c @connection=#<SQLite3::Database:0x3462c44 @statement_factory=SQLite3::Statement, @results_as_hash=true, @transaction_active=false, @handle=#<SWIG::TYPE_p_sqlite3:0x34522a4>, @translator=nil, @driver=#<SQLite3::Driver::Native::Driver:0x345236c @callback_data={}, @trace={}, @busy_handler={}, @authorizer={}>, @type_translation=false, @closed=false>, @last_verification=0, @runtime=0, @logger=#<Logger:0x367331c @logdev=#<Logger::LogDevice:0x3673164 @filename="script/../config/../config/../log/development.log", @mutex=#<Logger::LogDevice::LogDeviceMutex:0x3673074 @mon_owner=nil, @mon_waiting_queue=, @mon_entering_queue=, @mon_count=0>, @dev=#<File:script/../config/../config/../log/development.log>, @shift_size=1048576, @shift_age=0>, @formatter=nil, @default_formatter=#<Logger::Formatter:0x36731f0 @datetime_format=nil>, @level=0, @progname=nil>>

>> c.execute ' create table foos( a text, b text ) '
=>

>> class Foo < ActiveRecord::Base; end
=> nil

>> Foo.create :a => '4', :b => '2'
=> #<Foo:0x344a3c4 @errors=#<ActiveRecord::Errors:0x3447b10 @errors={}, @base=#<Foo:0x344a3c4 ...>>, @attributes={"a"=>"4", "b"=>"2", "id"=>1}, @new_record=false>

>> Foo.find_by_a '4'
=> #<Foo:0x3443ec0 @attributes={"a"=>"4", "b"=>"2"}>

>> Foo.find_by_b '2'
=> #<Foo:0x34419a4 @attributes={"a"=>"4", "b"=>"2"}>

>> require 'arrayfields'
=> ["ArrayFields", "Fieldedarray", "Arrayfields", "PseudoHash", "Fieldable", "Pseudohash", "FieldedArray"]

>> p Arrayfields.version
"4.2.0"
=> nil

>> Foo.find_by_a '4'
=> #<Foo:0x342bfb4 @attributes={"a"=>"4", "b"=>"2"}>

>> Foo.find_by_b '2'
=> #<Foo:0x3429a98 @attributes={"a"=>"4", "b"=>"2"}>

on rubyforge now.

a @ http://drawohara.com/

···

On Sep 18, 2007, at 8:41 AM, Stephen Bannasch wrote:
--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Bug for you...

    % cat af-bug.rb
    require 'rubygems'
    require 'arrayfields'
    puts "ruby version : #{RUBY_VERSION}"
    puts "gems version : #{Gem::RubyGemsVersion}"
    puts "arrayfields version : #{ArrayFields::VERSION}"
    require 'rake'
    puts 42

    % ruby af-bug.rb
    ruby version : 1.8.6
    gems version : 0.9.2
    arrayfields version : 4.1.0
    /opt/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:28:in `initialize': <nil> not inject-able (ArgumentError)
            from /opt/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
            from /opt/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
            from /opt/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:286:in `fields='
            from /opt/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:305:in `dup'
            from /opt/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake.rb:1304
            from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `gem_original_require'
            from /opt/local/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:32:in `require'
            from af-bug.rb:6

Order matters, require 'rake' before arrayfields and there is no error.

enjoy,

-jeremy

···

On Sat, Sep 15, 2007 at 01:24:22PM +0900, ara.t.howard wrote:

On Sep 14, 2007, at 9:36 PM, Morton Goldberg wrote:

>Surely, the last line above contains a typo. Shouldn't it be
>
>> p a['zero'] #=> 42
>
>Regards, Morton
>

therein lies the problem with writing documentation :wink:

if you check most of my new stuff the examples generate the README
for exactly the reason that i have fat fingers :wink:

thx.

--

Jeremy Hinegardner jeremy@hinegardner.org

yeah thanks. it was a stupid bug on my part. 4.2.0 and 4.3.0 both address the fix. thanks again.

a @ http://drawohara.com/

···

On Sep 18, 2007, at 1:27 PM, Stephen Bannasch wrote:

At 11:41 PM +0900 9/18/07, Stephen Bannasch wrote:

There appears to be an incompatibility between arrayfields and active record dynamic finders.

I've filed a bug report here:

http://rubyforge.org/tracker/index.php?func=detail&aid=14040&group_id=1024&atid=4025

Here's a much simpler way to generate the problem without rails.

$ irb
irb(main):001:0> a = [1,2,3]
=> [1, 2, 3]
irb(main):002:0> a.dup
=> [1, 2, 3]
irb(main):003:0> require 'arrayfields'
=> true
irb(main):004:0> a.dup
ArgumentError: <nil> not inject-able
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:28:in `initialize'
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:16:in `new'
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:286:in `fields='
        from /usr/local/lib/ruby/gems/1.8/gems/arrayfields-4.1.0/lib/arrayfields.rb:305:in `dup'
        from (irb):4

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

thanks.

cfp:~/src/ruby/arrayfields/arrayfields-4.2.0 > cat a.rb
require 'rubygems'
require 'arrayfields'
puts "ruby version : #{RUBY_VERSION}"
puts "gems version : #{Gem::RubyGemsVersion}"
puts "arrayfields version : #{ArrayFields::VERSION}"
require 'rake'
puts 42

cfp:~/src/ruby/arrayfields/arrayfields-4.2.0 > ruby a.rb
ruby version : 1.8.6
gems version : 0.9.2
arrayfields version : 4.2.0
42

on rubyforge now.

a @ http://drawohara.com/

···

On Sep 17, 2007, at 4:49 PM, Jeremy Hinegardner wrote:

Bug for you...

    % cat af-bug.rb
    require 'rubygems'
    require 'arrayfields'
    puts "ruby version : #{RUBY_VERSION}"
    puts "gems version : #{Gem::RubyGemsVersion}"
    puts "arrayfields version : #{ArrayFields::VERSION}"
    require 'rake'
    puts 42

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama