Permalink
Browse files

Adding README

  • Loading branch information...
1 parent fc03a24 commit 12449988586fbb2a75a378bc1864a3e3b0143a53 Michael Bleigh committed Nov 12, 2009
Showing with 200 additions and 18 deletions.
  1. +1 −1 LICENSE
  2. +63 −6 README.rdoc
  3. +4 −3 Rakefile
  4. +2 −1 lib/hashie.rb
  5. +72 −0 lib/hashie/dash.rb
  6. +58 −0 spec/hashie/dash_spec.rb
  7. +0 −7 spec/hashie_spec.rb
View
@@ -1,4 +1,4 @@
-Copyright (c) 2009 Michael Bleigh
+Copyright (c) 2009 Intridea, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
View
@@ -3,17 +3,74 @@
Hashie is a growing collection of tools that extend Hashes and make
them more useful.
+== Installation
+
+Hashie is a gem and is available on Gemcutter. If you don't have Gemcutter,
+install it:
+
+ gem install gemcutter
+ gem tumble
+
+Then you can install Hashie:
+
+ gem install hashie
+
+== Mash
+
+Mash is an extended Hash that gives simple pseudo-object functionality
+that can be built from hashes and easily extended. It is designed to
+be used in RESTful API libraries to provide easy object-like access
+to JSON and XML parsed hashes.
+
+=== Example:
+
+ mash = Hashie::Mash.new
+ mash.name? # => false
+ mash.name # => nil
+ mash.name = "My Mash"
+ mash.name # => "My Mash"
+ mash.name? # => true
+ mash.inspect # => <Hashie::Mash name="My Mash">
+
+ mash = Mash.new
+ # use bang methods for multi-level assignment
+ mash.author!.name = "Michael Bleigh"
+ mash.author # => <Hashie::Mash name="Michael Bleigh">
+
+== Dash
+
+Dash is an extended Hash that has a discrete set of defined properties
+and only those properties may be set on the hash. Additionally, you
+can set defaults for each property.
+
+=== Example:
+
+ class Person < Hashie::Dash
+ property :name
+ property :email
+ property :occupation, :default => 'Rubyist'
+ end
+
+ p = Person.new
+ p.name # => nil
+ p.occupation # => 'Rubyist'
+ p.email = 'abc@def.com'
+ p.email # => 'abc@def.com'
+ p['awesome'] # => NoMethodError
+
+
== Note on Patches/Pull Requests
* Fork the project.
* Make your feature addition or bug fix.
-* Add tests for it. This is important so I don't break it in a
- future version unintentionally.
-* Commit, do not mess with rakefile, version, or history.
- (if you want to have your own version, that is fine but
- bump version in a commit by itself I can ignore when I pull)
+* Add tests for it. This is important so I don't break it in a future version unintentionally.
+* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
* Send me a pull request. Bonus points for topic branches.
+== Authors
+
+* Michael Bleigh
+
== Copyright
-Copyright (c) 2009 Michael Bleigh. See LICENSE for details.
+Copyright (c) 2009 Intridea, Inc (http://intridea.com/). See LICENSE for details.
View
@@ -5,14 +5,15 @@ begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "hashie"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{Your friendly neighborhood hash toolkit.}
+ gem.description = %Q{Hashie is a small collection of tools that make hashes more powerful. Currently includes Mash (Mocking Hash) and Dash (Discrete Hash).}
gem.email = "michael@intridea.com"
- gem.homepage = "http://github.com/mbleigh/hashie"
+ gem.homepage = "http://github.com/intridea/hashie"
gem.authors = ["Michael Bleigh"]
gem.add_development_dependency "rspec"
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
end
+ Jeweler::GemcutterTasks.new
rescue LoadError
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
end
View
@@ -1,3 +1,4 @@
require 'hashie/hash_extensions'
require 'hashie/hash'
-require 'hashie/mash'
+require 'hashie/mash'
+require 'hashie/dash'
View
@@ -0,0 +1,72 @@
+require 'hashie/hash'
+
+module Hashie
+ # A Dash is a 'defined' or 'discrete' Hash, that is, a Hash
+ # that has a set of defined keys that are accessible (with
+ # optional defaults) and only those keys may be set or read.
+ #
+ # Dashes are useful when you need to create a very simple
+ # lightweight data object that needs even fewer options and
+ # resources than something like a DataMapper resource.
+ #
+ # It is preferrable to a Struct because of the in-class
+ # API for defining properties as well as per-property defaults.
+ class Dash < Hashie::Hash
+ # Defines a property on the Dash. Options are
+ # as follows:
+ #
+ # * <tt>:default</tt> - Specify a default value for this property,
+ # to be returned before a value is set on the property in a new
+ # Dash.
+ #
+ def self.property(property_name, options = {})
+ property_name = property_name.to_sym
+
+ (@properties ||= []) << property_name
+ (@defaults ||= {})[property_name] = options.delete(:default)
+
+ class_eval <<-RUBY
+ def #{property_name}
+ self['#{property_name}']
+ end
+
+ def #{property_name}=(val)
+ self['#{property_name}'] = val
+ end
+ RUBY
+ end
+
+ # Get a String array of the currently defined
+ # properties on this Dash.
+ def self.properties
+ @properties.collect{|p| p.to_s}
+ end
+
+ # Check to see if the specified property has already been
+ # defined.
+ def self.property?(prop)
+ properties.include?(prop.to_s)
+ end
+
+ # The default values that have been set for this Dash
+ def self.defaults
+ @defaults
+ end
+
+ # Retrieve a value from the Dash (will return the
+ # property's default value if it hasn't been set).
+ def [](property_name)
+ super || self.class.defaults[property_name.to_sym]
+ end
+
+ # Set a value on the Dash in a Hash-like way. Only works
+ # on pre-existing properties.
+ def []=(property, value)
+ if self.class.property?(property)
+ super
+ else
+ raise NoMethodError, 'You may only set pre-defined properties.'
+ end
+ end
+ end
+end
View
@@ -0,0 +1,58 @@
+require File.dirname(__FILE__) + '/../spec_helper'
+
+class DashTest < Hashie::Dash
+ property :first_name
+ property :email
+ property :count, :default => 0
+end
+
+describe Hashie::Dash do
+ it 'should be a subclass of Hashie::Hash' do
+ (Hashie::Dash < Hash).should be_true
+ end
+
+ describe ' creating properties' do
+ it 'should add the property to the list' do
+ DashTest.property :not_an_att
+ DashTest.properties.include?('not_an_att').should be_true
+ end
+
+ it 'should create a method for reading the property' do
+ DashTest.new.respond_to?(:first_name).should be_true
+ end
+
+ it 'should create a method for writing the property' do
+ DashTest.new.respond_to?(:first_name=).should be_true
+ end
+ end
+
+ describe ' writing to properties' do
+ before do
+ @dash = DashTest.new
+ end
+
+ it 'should not be able to write to a non-existent property using []=' do
+ lambda{@dash['abc'] = 123}.should raise_error(NoMethodError)
+ end
+
+ it 'should be able to write to an existing property using []=' do
+ lambda{@dash['first_name'] = 'Bob'}.should_not raise_error
+ end
+
+ it 'should be able to read/write to an existing property using a method call' do
+ @dash.first_name = 'Franklin'
+ @dash.first_name.should == 'Franklin'
+ end
+ end
+
+ describe ' defaults' do
+ before do
+ @dash = DashTest.new
+ end
+
+ it 'should return the default value for defaulted' do
+ DashTest.property :defaulted, :default => 'abc'
+ DashTest.new.defaulted.should == 'abc'
+ end
+ end
+end
View
@@ -1,7 +0,0 @@
-require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
-
-describe "Hashie" do
- it "fails" do
- fail "hey buddy, you should probably rename this file and start specing for real"
- end
-end

0 comments on commit 1244998

Please sign in to comment.