Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Add simple Person class

This class is backed by Hashidator and a simple class based on the Dash
from Hashie.
  • Loading branch information...
commit 03f37db332edecd2fa8e17cd0d70612207077198 1 parent a3e6aba
@namelessjon authored
View
8 Rakefile
@@ -0,0 +1,8 @@
+# Rakefile for phedre
+# Jonathan D. Stott <jonathan.stott@gmail.com>
+task :test do
+ require 'baretest'
+ BareTest::CommandLine.run([], :format => 'cli')
+end
+
+task :default => :test
View
44 app.rb
@@ -4,6 +4,17 @@
require 'mongo'
require 'hashidator'
require 'black_book/views'
+require 'lib/hash'
+
+
+class Person < DefinedHash
+ property :_id, BSON::ObjectID, :optional => true
+ property :name, String
+ property :page, String
+ property :numbers, [{:name => String, :number => String }], :optional => true
+ property :emails, [{:name => String, :email => String }], :optional => true
+ property :addresses, [{:name => String, :address => String, :postcode => String, :country => String }], :optional => true
+end
module BlackBook
@@ -19,14 +30,6 @@ class App < ::Sinatra::Base
set :name, 'BlackBook'
set :collection, 'people'
- set :validator, Hashidator.new(
- 'name' => String,
- 'page' => String,
- 'numbers' => proc { |v| v.nil? ? true : [{'name' => String, 'number' => String } ] },
- 'emails' => proc { |v| v.nil? ? true : [{'name' => String, 'email' => String } ] },
- 'addresses' => proc { |v| v.nil? ? true : [{'name' => String, 'address' => String, 'postcode' => String, 'country' => String } ] },
- )
-
helpers do
def people
settings.mongo[settings.collection]
@@ -70,28 +73,26 @@ def clean_params(param_set=params)
end
get '/:page' do |page|
- @person = people.find_one(:page => page)
- not_found unless @person
+ person = people.find_one(:page => page)
+ not_found unless person
+ @person = Person.new(person)
mustache :show
end
get '/:page/edit' do |page|
- @person = people.find_one(:page => page) || {'page' => page}
+ @person = Person.new(people.find_one(:page => page) || {'page' => page})
mustache :edit
end
post '/:page' do |page|
throw :halt, [400, "Need a person in there to hold addresses"] unless params['person'] and Hash === params['person']
# clean up the params
- params.delete_if { |k,v| "person" != k }
- params['person'].delete_if { |k,v| !%w|name numbers emails addresses|.include?(k) }
- params['person']['page'] = page
clean_params
- @person = people.find_one({:page => page}) || {}
+ @person = Person.new(people.find_one({:page => page}) || {})
@person.merge!(params['person'])
- if settings.validator.validate(@person)
+ if @person.valid?
people.save(@person)
redirect "/#{page}"
else
@@ -102,16 +103,15 @@ def clean_params(param_set=params)
post '/' do
throw :halt, [400, "Need a person in there to hold addresses"] unless params['person'] and Hash === params['person']
# clean up the params
- params.delete_if { |k,v| "person" != k }
- params['person'].delete_if { |k,v| !%w|name page numbers emails addresses|.include?(k) }
clean_params
- @person = people.find_one({:page => params['page']}, :fields => [:_id]) || {}
+ @person = Person.new(people.find_one({:page => params['page']}, :fields => [:_id]) || {})
@person.merge!(params['person'])
- if settings.validator.validate(@person)
- people.save(@person)
- redirect "/#{@person['page']}"
+ if @person.valid?
+ p @person
+ people.save(@person.to_hash)
+ redirect "/#{@person[:page]}"
else
mustache :edit
end
View
2  black_book/views/edit.rb
@@ -8,7 +8,7 @@ def action
end
def new?
- !!@person['_id']
+ !!@person[:_id]
end
def new_or_edit
View
10 black_book/views/person.rb
@@ -8,23 +8,23 @@ def title
end
def name
- @person['name']
+ @person[:name]
end
def page
- @person['page']
+ @person[:page]
end
def emails
- @person['emails']
+ @person[:emails]
end
def addresses
- @person['addresses']
+ @person[:addresses]
end
def numbers
- @person['numbers']
+ @person[:numbers]
end
end
end
View
2  black_book/views/show.rb
@@ -5,7 +5,7 @@ module Views
class Show < Person
def addresses
if addresses = super
- addresses.map! { |a| a['lines'] = a['address'].split(/\r?\n/).map! { |l| { :line => l } }; a }
+ addresses.map! { |a| a[:lines] = a[:address].split(/\r?\n/).map! { |l| { :line => l } }; a }
addresses
else
addresses
View
77 lib/hash.rb
@@ -0,0 +1,77 @@
+#!/usr/bin/ruby
+# Jonathan D. Stott <jonathan.stott@gmail.com>
+require 'hashidator'
+
+# A hash with defined keys
+#
+# This is somewhat similar to the 'Dash' provided by Hashie, but it has
+# hashidator validations baked in, and in addition, supports the idea of
+# optional columns. It also allows for sensible merging of such values.
+class DefinedHash < Hash
+
+ def initialize(attributes={})
+ self.class.add_properties(self.class.properties, self, attributes)
+ end
+
+
+ def self.property(name, type, opts={})
+ validator = opts.fetch(:optional, false) ? proc { |v| v.nil? ? true : type } : type
+ (@properties ||= {})[name] = type
+ (@validations ||= {})[name] = validator
+ end
+
+ def self.properties
+ (@properties || {})
+ end
+
+ def self.validations
+ (@validations || {})
+ end
+
+ def self.add_properties(properties, hash, attributes)
+ properties.each do |name, type|
+ add_property(hash, attributes, name, type)
+ end
+ end
+
+ def self.add_property(hash, attributes, name, type)
+ case type
+ when Array
+ value = attributes[name] if attributes.has_key?(name)
+ value = attributes[name.to_s] if attributes.has_key?(name.to_s)
+ if value
+ case type.first
+ when Hash
+ hash[name] = []
+ value = (Array === value) ? value : [value]
+ value.each do |v|
+ hash[name] << {}
+ add_properties(type.first, hash[name].last, v)
+ end
+ else
+ hash[name] = (Array === value) ? value : [value]
+ end
+ end
+ else
+ hash[name] = attributes[name] if attributes.has_key?(name)
+ hash[name] = attributes[name.to_s] if attributes.has_key?(name.to_s)
+ end
+ end
+
+
+ def valid?
+ Hashidator.validate(self.class.validations, self)
+ end
+
+ def merge!(hash)
+ self.class.add_properties(self.class.properties, self, hash)
+ end
+
+ def to_hash
+ out = {}
+ keys.each do |k|
+ out[k] = self[k]
+ end
+ out
+ end
+end
View
2  test/setup.rb
@@ -0,0 +1,2 @@
+$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
+require 'baretest'
View
120 test/suite/lib/hash.rb
@@ -0,0 +1,120 @@
+#!/usr/bin/ruby
+# Jonathan D. Stott <jonathan.stott@gmail.com>
+require 'hash'
+BareTest.suite "DefinedHash" do
+ setup do
+ class ::Person < DefinedHash
+ property :name, String
+ property :page, String
+ end
+ end
+
+ teardown do
+ Object.send(:remove_const, :Person)
+ end
+
+ suite ".properties" do
+ assert "properties list is correct" do
+ equal(Person.properties, {:name => String, :page => String})
+ end
+ end
+
+ suite ".new", :provides => :new do
+ assert "Basic .new works" do
+ Person.new
+ end
+
+ assert ".new with properties works" do
+ Person.new(:name => 'foo')
+ end
+
+ assert ".new with invalid properties works" do
+ Person.new(:name => 'foo', :num => 1)
+ end
+ end
+
+ suite "A DefinedHash", :depends_on => :new do
+ setup do
+ @person = Person.new(:name => 'Bob', 'page' => 'bob', :num => 1)
+ end
+
+ assert "has valid properties set" do
+ @person[:name] == 'Bob'
+ end
+
+ assert "has strings set" do
+ @person[:page] == 'bob'
+ end
+
+ assert "Doesn't have non-valid keys set" do
+ @person.has_key?(:num) == false
+ end
+ end
+
+ suite "Array properties", :depends_on => :new do
+ setup do
+ class ::Person
+ property :numbers, [String]
+ property :emails, [{:name => String}]
+ end
+ end
+
+ assert "An array property is assigned as an array" do
+ @person = Person.new(:numbers => %w{5551234})
+ equal_unordered(%w{5551234}, @person[:numbers])
+ end
+
+ assert "A non-array property is assigned as an array" do
+ @person = Person.new(:numbers => "5551234")
+ equal_unordered(%w{5551234}, @person[:numbers])
+ end
+
+ assert "A hash in array is added properly" do
+ @person = Person.new(:emails => { 'name' => 'gmail', :foo => 'bar'})
+ equal_unordered([{:name => 'gmail'}], @person[:emails])
+ end
+ assert "A hash in array is added properly" do
+ @person = Person.new(:emails => [{ 'name' => 'gmail', :foo => 'bar'}])
+ equal_unordered([{:name => 'gmail'}], @person[:emails])
+ end
+ end
+
+
+
+ suite "Testing validity", :depends_on => :new do
+ setup do
+ class ::Person
+ property :nick, String, :optional => true
+ end
+ end
+
+ suite "invalid" do
+ setup :invalid_person, [
+ {:name => 'name'},
+ {:page => 'page'},
+ { :name => 'name', :page => 1 },
+ { :name => 1, :page => 'page' },
+ {:name => 'name', :page => 'page', :nick => 2 }
+ ] do |invalid_person|
+ @person = Person.new(invalid_person)
+ end
+
+ assert ":invalid_person is invalid" do
+ @person.valid? == false
+ end
+ end
+
+ suite "valid" do
+ setup :valid_person, [
+ {:name => 'name', :page => 'page'},
+ {:name => 'name', :page => 'page', :nick => 'namz' }
+ ] do |valid_person|
+ @person = Person.new(valid_person)
+ end
+
+ assert ":valid_person is valid" do
+ @person.valid? == true
+ end
+ end
+ end
+end

0 comments on commit 03f37db

Please sign in to comment.
Something went wrong with that request. Please try again.