ahoward / map Goto Github PK
View Code? Open in Web Editor NEWthe ruby container you've always wanted: an ordered string/symbol indifferent hash
License: Other
the ruby container you've always wanted: an ordered string/symbol indifferent hash
License: Other
NAME map.rb SYNOPSIS the awesome ruby container you've always wanted: a string/symbol indifferent ordered hash that works in all rubies maps are bitchin ordered hashes that are both ordered, string/symbol indifferent, and have all sorts of sweetness like recursive conversion, more robust implementation than HashWithIndifferentAccess, support for struct like (map.foo) access, and support for option/keyword access which avoids several nasty classes of errors in many ruby libraries INSTALL gem install map URI http://github.com/ahoward/map DESCRIPTION # maps are always ordered. constructing them in an ordered fashion builds # them that way, although the normal hash contructor is also supported # m = Map[:k, :v, :key, :val] m = Map(:k, :v, :key, :val) m = Map.new(:k, :v, :key, :val) m = Map[[:k, :v], [:key, :val]] m = Map(:k => :v, :key => :val) # ruh-oh, the input hash loses order! m = Map.new(:k => :v, :key => :val) # ruh-oh, the input hash loses order! m = Map.new m[:a] = 0 m[:b] = 1 m[:c] = 2 p m.keys #=> ['a','b','c'] ### always ordered! p m.values #=> [0,1,2] ### always ordered! # maps don't care about symbol vs.string keys # p m[:a] #=> 0 p m["a"] #=> 0 # even via deep nesting # p m[:foo]['bar'][:baz] #=> 42 # many functions operate in a way one would expect from an ordered container # m.update(:k2 => :v2) m.update(:k2, :v2) key_val_pair = m.shift key_val_pair = m.pop # maps keep mapiness for even deep operations # m.update :nested => {:hashes => {:are => :converted}} # maps can give back clever little struct objects # m = Map(:foo => {:bar => 42}) s = m.struct p s.foo.bar #=> 42 # because option parsing is such a common use case for needing string/symbol # indifference map.rb comes out of the box loaded with option support # def foo(*args, &block) opts = Map.options(args) a = opts.getopt(:a) b = opts.getopt(:b, :default => false) end opts = Map.options(:a => 42, :b => nil, :c => false) opts.getopt(:a) #=> 42 opts.getopt(:b) #=> nil opts.getopt(:b, :default => 42) #=> 42 opts.getopt(:c) #=> false opts.getopt(:d, :default => false) #=> false # this avoids such bugs as # options = {:read_only => false} read_only = options[:read_only] || true # should be false but is true # with options this becomes # options = Map.options(:read_only => true) read_only = options.getopt(:read_only, :default => false) #=> true # maps support some really nice operators that hashes/orderedhashes do not # m = Map.new m.set(:h, :a, 0, 42) m.has?(:h, :a) #=> true p m #=> {'h' => {'a' => [42]}} m.set(:h, :a, 1, 42.0) p m #=> {'h' => {'a' => [42, 42.0]}} m.get(:h, :a, 1) #=> 42.0 m.get(:x, :y, :z) #=> nil m[:x][:y][:z] #=> raises exception! m = Map.new(:array => [0,1]) defaults = {:array => [nil, nil, 2]} m.apply(defaults) p m[:array] #=> [0,1,2] # they also support some different iteration styles # m = Map.new m.set( [:a, :b, :c, 0] => 0, [:a, :b, :c, 1] => 10, [:a, :b, :c, 2] => 20, [:a, :b, :c, 3] => 30 ) m.set(:x, :y, 42) m.set(:x, :z, 42.0) m.depth_first_each do |key, val| p key => val end #=> [:a, :b, :c, 0] => 0 #=> [:a, :b, :c, 1] => 10 #=> [:a, :b, :c, 2] => 20 #=> [:a, :b, :c, 3] => 30 #=> [:x, :y] => 42 #=> [:x, :z] => 42.0 USAGE see lib/map.rb and test/map_test.rb HISTORY 4.3.0: - support for dot keys. map.set('a.b.c' => 42) #=> {'a'=>{'b'=>{'c'=>42}}}
Output from 'irb':
require 'map' #=> true
m = Map[1, Map[2, 3]] #=> {1=>{2=>3}}
m.reject { |a, b| p [a, b] } #=> {1=>{2=>3}}
[1, nil]
If value is map, then reject sees it as nil. Other methods seems to work fine (#each, #select).
RubyGems.org doesn't report a license for your gem. This is because it is not specified in the gemspec of your last release.
via e.g.
spec.license = 'MIT'
# or
spec.licenses = ['MIT', 'GPL-2']
Including a license in your gemspec is an easy way for rubygems.org and other tools to check how your gem is licensed. As you can imagine, scanning your repository for a LICENSE file or parsing the README, and then attempting to identify the license or licenses is much more difficult and more error prone. So, even for projects that already specify a license, including a license in your gemspec is a good practice. See, for example, how rubygems.org uses the gemspec to display the rails gem license.
There is even a License Finder gem to help companies/individuals ensure all gems they use meet their licensing needs. This tool depends on license information being available in the gemspec. This is an important enough issue that even Bundler now generates gems with a default 'MIT' license.
I hope you'll consider specifying a license in your gemspec. If not, please just close the issue with a nice message. In either case, I'll follow up. Thanks for your time!
Appendix:
If you need help choosing a license (sorry, I haven't checked your readme or looked for a license file), GitHub has created a license picker tool. Code without a license specified defaults to 'All rights reserved'-- denying others all rights to use of the code.
Here's a list of the license names I've found and their frequencies
p.s. In case you're wondering how I found you and why I made this issue, it's because I'm collecting stats on gems (I was originally looking for download data) and decided to collect license metadata,too, and make issues for gemspecs not specifying a license as a public service :). See the previous link or my blog post about this project for more information.
Great library! I've been thinking I want ordered hashes in JavaScript, and I think having a key containing the order would be preferable to using an array of single key objects instead. That is, I think for most cases, {"a": 1, "b": 2, "_order": ["b", "a"]}
would be more useful to me than [{"b": 2}, {"a": 1}]
. With the former, I can address a key like obj.a
. It also has fewer objects.
I made a first pass in my serialize_order branch. If it doesn't conflict with anything, I think it might be a good convenience method. It wouldn't work for serializing a complex data structure, though. I think overriding to_json might be the way to do that, but I'm not sure how to have options without making them global.
Hi...
Great code, great gem!
^_^
But running the test I've found a test that fail due a bang
:
eddie@white:~/Coding/map$ ruby test/map_test.rb
Loaded suite test/map_test
Started
................E
===============================================================================
Error: test_00016_simple-struct-usage(TESTING_001_MAP)
IndexError: !
/home/eddie/Coding/map/lib/map/struct.rb:27:in `method_missing'
/home/eddie/Coding/map/test/lib/testing.rb:47:in `assert'
test/map_test.rb:178:in `block (2 levels) in <main>'
===============================================================================
E
===============================================================================
Error: test_00017_nested-struct-usage(TESTING_001_MAP)
IndexError: !
/home/eddie/Coding/map/lib/map/struct.rb:27:in `method_missing'
/home/eddie/Coding/map/test/lib/testing.rb:47:in `assert'
test/map_test.rb:185:in `block (2 levels) in <main>'
===============================================================================
.......................................
Finished in 0.264128141 seconds.
57 tests, 4952 assertions, 0 failures, 2 errors, 0 pendings, 0 omissions, 0 notifications
96.4912% passed
With jruby (jruby 1.5.6 (ruby 1.8.7 patchlevel 249) (2011-06-08 6586) (Java HotSpot(TM) 64-Bit Server VM 1.6.0_26) [amd64-java]) I get the following test failure:
/var/tmp/portage/dev-ruby/map-4.2.0/work/all/map-4.2.0/test/lib/testing.rb:23:in `Testing': undefined method `slug_for' for #<Class:01x11ba4159> (NoMethodError)
from /var/tmp/portage/dev-ruby/map-4.2.0/work/all/map-4.2.0/test/lib/testing.rb:6:in `initialize'
from /var/tmp/portage/dev-ruby/map-4.2.0/work/all/map-4.2.0/test/lib/testing.rb:6:in `new'
from /var/tmp/portage/dev-ruby/map-4.2.0/work/all/map-4.2.0/test/lib/testing.rb:6:in `Testing'
from /var/tmp/portage/dev-ruby/map-4.2.0/work/all/map-4.2.0/test/map_test.rb:4
Changing "def This.slug_for" to "def self.sluf_for" seems to fix this, and with this change the test suite still passes on ruby 1.8.7 and ruby enterprise edition. Haven't tried ruby 1.9.
Latest release of the "map" gem is 4.2.0
The library fails to load with an ArgumentError for Ruby 1.9.2 p136. Attached patches fix the loading and a typo in the code, but the tests still don't pass. The reason for this seems to be that the new Ruby calls 'inherited' before executing the block of Class.new do ... end. Therefore classes don't have names yet at #inherited.
https://gist.github.com/757123
greetings
With ruby 1.8.7 (2012-06-29 patchlevel 370) [x86_64-linux] I'm seeing the following test failure:
=======================================================================================================================
@1 => /usr/bin/ruby18 -I ./lib -I ./test/lib /var/tmp/portage/dev-ruby/map-6.2.0/work/ruby18/map-6.2.0/test/map_test.rb
-----------------------------------------------------------------------------------------------------------------------
/var/tmp/portage/dev-ruby/map-6.2.0/work/ruby18/map-6.2.0/test/map_test.rb:420: syntax error, unexpected ')'
/var/tmp/portage/dev-ruby/map-6.2.0/work/ruby18/map-6.2.0/test/map_test.rb:764: syntax error, unexpected $end, expecting kEND
-----------------------------------------------------------------------------------------------------------------------
@1 <= FAILURE
-----------------------------------------------------------------------------------------------------------------------
Map#keep_if (from Hash) sets values to nil
as opposed to deleting key/value pair
A failing test:
testing 'that Map#keep_if properly removes k/v pairs for which the passed block evaluates to false' do
m = Map.new( { 1 => "hi" , 2 => "there" } )
puts m.keep_if { |k,v| k == 2 }.inspect
assert{ !( m.keep_if { |k,v| k == 2 }.keys.include? 1 ) }
end
It is not clear under what license the code is release. Could you add licensing information?
Map.new('a' => 1).symbolize_keys.should == {:a => 1}
Maybe this is not really a bug, but not the way I expected the structure to begin, because it is inconsistent with Hash.
h = {}
(h[:a] ||= []) << :b
# h is now {:a=>[:b]}
m = Map.new
(m[:a] ||= []) << :b
# m is now {:a=>[]}
This helps to understand:
(m[:a] = {}).class # Hash
m[:a].class # Map
(m[:a] = {})[:b] = :c # m is {:a=>{}}
m[:a] = {}; m[:a][:b] = :c # m is {:a=>{:b=>:c}}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.