Skip to content
Browse files

initial commit, attributes and elements with primitive types work

  • Loading branch information...
0 parents commit 9d8c6310e5be27af026795d900573f5b98ada6ca @jnunemaker committed Aug 14, 2008
4 History.txt
@@ -0,0 +1,4 @@
+== 0.1.0 2008-08-13
+
+* 1 major enhancement:
+ * Initial release
20 License.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2008 John Nunemaker
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 Manifest.txt
@@ -0,0 +1,27 @@
+History.txt
+License.txt
+Manifest.txt
+PostInstall.txt
+README.txt
+Rakefile
+config/hoe.rb
+config/requirements.rb
+lib/happymapper.rb
+lib/happymapper/version.rb
+script/console
+script/destroy
+script/generate
+script/txt2html
+setup.rb
+spec/happymapper_spec.rb
+spec/spec.opts
+spec/spec_helper.rb
+tasks/deployment.rake
+tasks/environment.rake
+tasks/rspec.rake
+tasks/website.rake
+website/index.html
+website/index.txt
+website/javascripts/rounded_corners_lite.inc.js
+website/stylesheets/screen.css
+website/template.html.erb
7 PostInstall.txt
@@ -0,0 +1,7 @@
+
+For more information on happymapper, see http://happymapper.rubyforge.org
+
+NOTE: Change this information in PostInstall.txt
+You can also delete it if you don't want it.
+
+
48 README.txt
@@ -0,0 +1,48 @@
+= happymapper
+
+* FIX (url)
+
+== DESCRIPTION:
+
+FIX (describe your package)
+
+== FEATURES/PROBLEMS:
+
+* FIX (list of features or problems)
+
+== SYNOPSIS:
+
+ FIX (code sample of usage)
+
+== REQUIREMENTS:
+
+* FIX (list of requirements)
+
+== INSTALL:
+
+* FIX (sudo gem install, anything else)
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) 2008 John Nunemaker
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4 Rakefile
@@ -0,0 +1,4 @@
+require 'config/requirements'
+require 'config/hoe' # setup Hoe + all gem configuration
+
+Dir['tasks/**/*.rake'].each { |rake| load rake }
73 config/hoe.rb
@@ -0,0 +1,73 @@
+require 'happymapper/version'
+
+AUTHOR = 'John Nunemaker' # can also be an array of Authors
+EMAIL = "nunemaker@gmail.com"
+DESCRIPTION = "description of gem"
+GEM_NAME = 'happymapper' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'happymapper' # The unix name for your project
+HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
+DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
+EXTRA_DEPENDENCIES = [
+# ['activesupport', '>= 1.3.1']
+] # An array of rubygem dependencies [name, version]
+
+@config_file = "~/.rubyforge/user-config.yml"
+@config = nil
+RUBYFORGE_USERNAME = "unknown"
+def rubyforge_username
+ unless @config
+ begin
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
+ rescue
+ puts <<-EOS
+ERROR: No rubyforge config file found: #{@config_file}
+Run 'rubyforge setup' to prepare your env for access to Rubyforge
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
+ EOS
+ exit
+ end
+ end
+ RUBYFORGE_USERNAME.replace @config["username"]
+end
+
+
+REV = nil
+# UNCOMMENT IF REQUIRED:
+# REV = YAML.load(`svn info`)['Revision']
+VERS = HappyMapper::VERSION::STRING + (REV ? ".#{REV}" : "")
+RDOC_OPTS = ['--quiet', '--title', 'happymapper documentation',
+ "--opname", "index.html",
+ "--line-numbers",
+ "--main", "README",
+ "--inline-source"]
+
+class Hoe
+ def extra_deps
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
+ @extra_deps
+ end
+end
+
+# Generate all the Rake tasks
+# Run 'rake -T' to see list of generated tasks (from gem root directory)
+$hoe = Hoe.new(GEM_NAME, VERS) do |p|
+ p.developer(AUTHOR, EMAIL)
+ p.description = DESCRIPTION
+ p.summary = DESCRIPTION
+ p.url = HOMEPATH
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
+ p.test_globs = ["test/**/test_*.rb"]
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
+
+ # == Optional
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
+ #p.extra_deps = EXTRA_DEPENDENCIES
+
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
+ end
+
+CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
+PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
+$hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
+$hoe.rsync_args = '-av --delete --ignore-errors'
+$hoe.spec.post_install_message = File.open(File.dirname(__FILE__) + "/../PostInstall.txt").read rescue ""
15 config/requirements.rb
@@ -0,0 +1,15 @@
+require 'fileutils'
+include FileUtils
+
+require 'rubygems'
+%w[rake hoe newgem rubigen].each do |req_gem|
+ begin
+ require req_gem
+ rescue LoadError
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
+ puts "Installation: gem install #{req_gem} -y"
+ exit
+ end
+end
+
+$:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
11 examples/post.rb
@@ -0,0 +1,11 @@
+class Post
+ include HappyMapper
+
+ attribute :href, String
+ attribute :hash, String
+ attribute :description, String
+ attribute :tag, String
+ attribute :time, DateTime
+ attribute :others, Integer
+ attribute :extended, String
+end
143 lib/happymapper.rb
@@ -0,0 +1,143 @@
+$:.unshift(File.dirname(__FILE__)) unless
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
+
+require 'date'
+require 'time'
+require 'rubygems'
+gem 'libxml-ruby', '>= 0.8.3'
+require 'xml'
+
+class Boolean; end
+
+module HappyMapper
+
+ def self.included(base)
+ base.instance_variable_set("@attributes", {})
+ base.instance_variable_set("@elements", {})
+ base.extend ClassMethods
+ end
+
+ module ClassMethods
+ def attribute(name, type)
+ attribute = Attribute.new(name, type)
+ @attributes[to_s] ||= []
+ @attributes[to_s] << attribute
+ create_accessor(attribute.name)
+ end
+
+ def attributes
+ @attributes[to_s] || []
+ end
+
+ def element(name, type)
+ element = Element.new(name, type)
+ @elements[to_s] ||= []
+ @elements[to_s] << element
+ create_accessor(element.name)
+ end
+
+ def elements
+ @elements[to_s] || []
+ end
+
+ def tag_name(new_tag_name)
+ @tag_name = new_tag_name.to_s
+ end
+
+ def get_tag_name
+ @tag_name ||= to_s.downcase
+ end
+
+ def create_getter(name)
+ class_eval <<-EOS, __FILE__, __LINE__
+ def #{name}
+ @#{name}
+ end
+ EOS
+ end
+
+ def create_setter(name)
+ class_eval <<-EOS, __FILE__, __LINE__
+ def #{name}=(value)
+ @#{name} = value
+ end
+ EOS
+ end
+
+ def create_accessor(name)
+ create_getter(name)
+ create_setter(name)
+ end
+
+ def parse(xml)
+ parser = XML::Parser.new
+ parser.string = xml
+ doc = parser.parse
+ collection = []
+ doc.find(get_tag_name).each do |el|
+ obj = new
+ # TODO: reading value from xml should move to Item
+ attributes.each { |a| obj.send("#{a.name}=", a.typecast(el.attributes[a.xml_name])) }
+ elements.each { |e| obj.send("#{e.name}=", e.typecast(el.find(e.xml_name).first.content)) }
+ collection << obj
+ end
+ collection
+ end
+ end
+
+ class Item
+ attr_accessor :type, :xml_name
+ attr_reader :name
+
+ def initialize(name, type, o={})
+ self.name, self.type, self.xml_name = name, type, o.delete(:xml_name) || name.to_s
+ @options = {}.merge(o)
+ @xml_type = self.class.to_s.split('::').last.downcase
+ end
+
+ def name=(new_name)
+ @name = new_name.to_s
+ end
+
+ def typecast(value)
+ return value if value.kind_of?(type) || value.nil?
+ begin
+ if type == String then value.to_s
+ elsif type == Float then value.to_f
+ elsif type == Time then Time.parse(value.to_s)
+ elsif type == Date then Date.parse(value.to_s)
+ elsif type == DateTime then DateTime.parse(value.to_s)
+ elsif type == Boolean then ['true', 't', '1'].include?(value.to_s.downcase)
+ elsif type == Integer
+ # ganked from datamapper
+ value_to_i = value.to_i
+ if value_to_i == 0 && value != '0'
+ value_to_s = value.to_s
+ begin
+ Integer(value_to_s =~ /^(\d+)/ ? $1 : value_to_s)
+ rescue ArgumentError
+ nil
+ end
+ else
+ value_to_i
+ end
+ else
+ value
+ end
+ rescue
+ value
+ end
+ end
+
+ def element?
+ @xml_type == 'element'
+ end
+
+ def attribute?
+ @xml_type == 'attribute'
+ end
+ end
+
+ class Element < Item; end
+ class Attribute < Item; end
+end
9 lib/happymapper/version.rb
@@ -0,0 +1,9 @@
+module HappyMapper
+ module VERSION #:nodoc:
+ MAJOR = 0
+ MINOR = 1
+ TINY = 0
+
+ STRING = [MAJOR, MINOR, TINY].join('.')
+ end
+end
10 script/console
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+# File: script/console
+irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
+
+libs = " -r irb/completion"
+# Perhaps use a console_lib to store any extra methods I may want available in the cosole
+# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
+libs << " -r #{File.dirname(__FILE__) + '/../lib/happymapper.rb'}"
+puts "Loading happymapper gem"
+exec "#{irb} #{libs} --simple-prompt"
14 script/destroy
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/destroy'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
+RubiGen::Scripts::Destroy.new.run(ARGV)
14 script/generate
@@ -0,0 +1,14 @@
+#!/usr/bin/env ruby
+APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
+
+begin
+ require 'rubigen'
+rescue LoadError
+ require 'rubygems'
+ require 'rubigen'
+end
+require 'rubigen/scripts/generate'
+
+ARGV.shift if ['--help', '-h'].include?(ARGV[0])
+RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
+RubiGen::Scripts::Generate.new.run(ARGV)
82 script/txt2html
@@ -0,0 +1,82 @@
+#!/usr/bin/env ruby
+
+GEM_NAME = 'happymapper' # what ppl will type to install your gem
+RUBYFORGE_PROJECT = 'happymapper'
+
+require 'rubygems'
+begin
+ require 'newgem'
+ require 'rubyforge'
+rescue LoadError
+ puts "\n\nGenerating the website requires the newgem RubyGem"
+ puts "Install: gem install newgem\n\n"
+ exit(1)
+end
+require 'redcloth'
+require 'syntax/convertors/html'
+require 'erb'
+require File.dirname(__FILE__) + "/../lib/#{GEM_NAME}/version.rb"
+
+version = HappyMapper::VERSION::STRING
+download = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
+
+def rubyforge_project_id
+ RubyForge.new.autoconfig["group_ids"][RUBYFORGE_PROJECT]
+end
+
+class Fixnum
+ def ordinal
+ # teens
+ return 'th' if (10..19).include?(self % 100)
+ # others
+ case self % 10
+ when 1: return 'st'
+ when 2: return 'nd'
+ when 3: return 'rd'
+ else return 'th'
+ end
+ end
+end
+
+class Time
+ def pretty
+ return "#{mday}#{mday.ordinal} #{strftime('%B')} #{year}"
+ end
+end
+
+def convert_syntax(syntax, source)
+ return Syntax::Convertors::HTML.for_syntax(syntax).convert(source).gsub(%r!^<pre>|</pre>$!,'')
+end
+
+if ARGV.length >= 1
+ src, template = ARGV
+ template ||= File.join(File.dirname(__FILE__), '/../website/template.html.erb')
+else
+ puts("Usage: #{File.split($0).last} source.txt [template.html.erb] > output.html")
+ exit!
+end
+
+template = ERB.new(File.open(template).read)
+
+title = nil
+body = nil
+File.open(src) do |fsrc|
+ title_text = fsrc.readline
+ body_text_template = fsrc.read
+ body_text = ERB.new(body_text_template).result(binding)
+ syntax_items = []
+ body_text.gsub!(%r!<(pre|code)[^>]*?syntax=['"]([^'"]+)[^>]*>(.*?)</\1>!m){
+ ident = syntax_items.length
+ element, syntax, source = $1, $2, $3
+ syntax_items << "<#{element} class='syntax'>#{convert_syntax(syntax, source)}</#{element}>"
+ "syntax-temp-#{ident}"
+ }
+ title = RedCloth.new(title_text).to_html.gsub(%r!<.*?>!,'').strip
+ body = RedCloth.new(body_text).to_html
+ body.gsub!(%r!(?:<pre><code>)?syntax-temp-(\d+)(?:</code></pre>)?!){ syntax_items[$1.to_i] }
+end
+stat = File.stat(src)
+created = stat.ctime
+modified = stat.mtime
+
+$stdout << template.result(binding)
1,585 setup.rb
1,585 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
23 spec/fixtures/posts.xml
@@ -0,0 +1,23 @@
+<posts user="jnunemaker" tag="ruby">
+ <post href="http://roxml.rubyforge.org/" hash="19bba2ab667be03a19f67fb67dc56917" description="ROXML - Ruby Object to XML Mapping Library" tag="ruby xml gems mapping" time="2008-08-09T05:24:20Z" others="56" extended="ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes."/>
+ <post href="http://code.google.com/p/sparrow/" hash="1df8a7cb9e8960992556518c0ea0d146" description="sparrow - Google Code" tag="ruby sparrow memcache queue" time="2008-08-06T15:07:24Z" others="115" extended="Sparrow is a really fast lightweight queue written in Ruby that speaks memcache. That means you can use Sparrow with any memcached client library (Ruby or otherwise)."/>
+ <post href="http://code.google.com/p/query-reviewer/" hash="963187e8bf350ae42e21eee13a2bef07" description="query-reviewer - Google Code" tag="rails ruby railstips plugins database optimization" time="2008-08-04T21:50:14Z" others="180" extended="This rails plugin not only runs &quot;EXPLAIN&quot; before each of your select queries in development, but provides a small DIV in the rendered output of each page with the summary of query warnings that it analyzed."/>
+ <post href="http://dev.zeraweb.com/introducing-functor" hash="2cdd545934bd37ae6f4829c51b3041c5" description="dev.zeraweb.com: Introducing Functor" tag="ruby methods gems railstips" time="2008-08-04T21:46:47Z" others="61" extended="Really cool ruby lib for overloading method definitions. I can think of a few places this would be handy."/>
+ <post href="http://prawn.majesticseacreature.com/" hash="92764e019de7553b4cd38017e42e4aaa" description="prawn.majesticseacreature.com" tag="pdf ruby railstips" time="2008-08-04T21:26:20Z" others="237" extended="pure ruby pdf generation library."/>
+ <post href="http://meme-rocket.com/2006/09/28/ruby-moduleinclude-at-odds-with-duck-typing/" hash="4ce96c7c237161819e9625737c22b462" description="Bill Burcham’s memeRocket :: Ruby Module#include at Odds with Duck Typing." tag="ruby railstips enumerable comparable" time="2008-08-03T16:09:24Z" others="3" extended="How to build your own enumerable and comparable objects in ruby. This article is old but just came across it and found it handy."/>
+ <post href="http://bl.ogtastic.com/archives/2008/7" hash="6bebd138c037d7d7c88a7046ca03f671" description="The right way to do something you should never do" tag="juggernaut observers rails flash ruby" time="2008-08-03T03:50:58Z" others="0" extended="Example of how to use juggernaut with an observer."/>
+ <post href="http://ncavig.com/blog/?page_id=8" hash="55450d103d6e2dd609b203ad133d751f" description="Nic’s Notions » Juggernaut Tutorials" tag="juggernaut rails ruby flash plugins server chat" time="2008-08-03T02:26:39Z" others="30" extended="Several juggernaut tutorials."/>
+ <post href="http://blog.labnotes.org/2008/05/05/distributed-twitter-client-in-20-lines-of-code/" hash="7c2a36292db109b144036a02eb3f46b7" description="Labnotes » Distributed Twitter Client in 20 lines of code" tag="xmpp ruby jabber xmpp4r" time="2008-08-01T18:16:23Z" others="18" extended="Cool little snippet of xmpp goodness to check your buddies status messages."/>
+ <post href="http://labs.reevoo.com/plugins/beanstalk-messaging" hash="d100c10208acbf5e954320a5577838d9" description="reevoolabs - Beanstalk Messaging" tag="railstips messaging queue rails ruby" time="2008-07-28T02:57:00Z" others="33" extended="Good write up on beanstalk"/>
+ <post href="http://www.slideshare.net/guest807bb2/rubyfringe?src=embed" hash="c3dc3b940dbe25e39737240b4e1ab071" description="Rockstar Memcached" tag="memcached performance caching ruby rails railstips" time="2008-07-28T02:30:50Z" others="11" extended="Killer presentation on memcached by Tobi of Shopify."/>
+ <post href="http://www.igvita.com/2008/07/22/unix-signals-for-live-debugging/" hash="288054a38d870b15bdf060ed5c6b2a2e" description="Unix Signals for Live Debugging - igvita.com" tag="ruby signals unix debugging signal railstips" time="2008-07-27T04:53:00Z" others="86" extended="I've known how to kill processes and such but never quite understood kill. Ilya Grigorik explains not only how to send those signals but how to use them in your scripts to change the way they behave on the fly. Very cool."/>
+ <post href="http://www.rubyinside.com/redcloth-4-released-962.html" hash="b3db9b84940ce550e26a560b83eb2f66" description="RedCloth 4.0 Released: 40x Faster Textile Rendering" tag="textile ruby gems railstips" time="2008-07-27T04:42:29Z" others="20" extended="Redcloth gets some serious love. It's now much faster. Sweet!"/>
+ <post href="http://code.google.com/p/rubycas-server/" hash="b532ea5933e4eba76c44823e17fecd31" description="rubycas-server - Google Code" tag="sso authentication cas ruby" time="2008-07-22T17:04:09Z" others="132" extended="RubyCAS-Server provides a single sign-on solution for web applications, implementing the server-end of JA-SIG's CAS protocol."/>
+ <post href="http://reinh.com/blog/2008/07/14/a-thinking-mans-sphinx.html" hash="033d72ac54d8c722618383e0e2aa18ff" description="ReinH — A Thinking Man's Sphinx" tag="rails railstips sphinx search ruby" time="2008-07-17T19:34:59Z" others="142" extended="A guide to the two sphynx plugins: ultrasphynx and thinksphynx and why you should choose one or the other."/>
+ <post href="http://www.rubyinside.com/ruby-xml-crisis-over-libxml-0-8-0-released-955.html" hash="70490d9786f09db5ba5f7904f88d304c" description="libxml-ruby 0.8.0 Released: Ruby Gets Fast, Reliable XML Processing At Last" tag="libxml xml ruby gems" time="2008-07-17T18:22:23Z" others="55" extended="lib xml gets an update and now it's really fast."/>
+ <post href="http://github.com/RISCfuture/autumn/tree/master" hash="9b47db4bf59da2009642f4084e3113a2" description="autumn at master — GitHub" tag="irc ruby gems" time="2008-07-17T18:20:19Z" others="18" extended="Easy, fresh, feature-rich IRC bots in Ruby"/>
+ <post href="http://groups.google.com/group/datamapper/browse_thread/thread/d33fbb20e41fad04" hash="4403898c92b37788f002ad6d79a66b68" description="New Finder Syntax (before 1.0) -" tag="railstips ruby datamapper" time="2008-07-05T20:42:27Z" others="1" extended="really cool idea for conditions in datamapper. even if you don't use datamapper, read this as it's sweet."/>
+ <post href="http://codeclimber.blogspot.com/2008/06/using-ruby-for-imap-with-gmail.html" hash="33bbf2492beac5fbf1fc167014060067" description="CodeClimber: using Ruby for IMAP with Gmail" tag="email gems gmail google imap rails railstips ruby" time="2008-07-05T20:06:47Z" others="118" extended="how to check gmail using ruby's IMAP libraries. the key is to use the login method instead of the authenticate one."/>
+ <post href="http://xullicious.blogspot.com/2008/07/updated-curb-multi-interface-patch.html" hash="f95dcc012bdc13bc26bace3ceed10656" description="Xul for thought: Updated curb multi interface patch" tag="curl ruby http" time="2008-07-03T21:52:45Z" others="1" extended="Really cool multi curl stuff to rapidly hit urls."/>
+</posts>
+<!-- fe04.api.del.ac4.yahoo.net uncompressed/chunked Sat Aug 9 00:20:11 PDT 2008 -->
422 spec/fixtures/statuses.xml
@@ -0,0 +1,422 @@
+<statuses type="array">
+<status>
+ <created_at>Sat Aug 09 05:38:12 +0000 2008</created_at>
+ <id>882281424</id>
+ <text>I so just thought the guy lighting the Olympic torch was falling when he began to run on the wall. Wow that would have been catastrophic.</text>
+ <source>web</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>1234</in_reply_to_status_id>
+ <in_reply_to_user_id>12345</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Sat Aug 09 02:04:56 +0000 2008</created_at>
+ <id>882145663</id>
+ <text>@ijonas - wow that stuff sounds sweet</text>
+ <source>web</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>882005142</in_reply_to_status_id>
+ <in_reply_to_user_id>1000471</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Sat Aug 09 01:36:41 +0000 2008</created_at>
+ <id>882126691</id>
+ <text>Steph is driving Sally for the first time. I'm proud of her.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 22:21:21 +0000 2008</created_at>
+ <id>881987762</id>
+ <text>@ijonas - what are you making with couchdb, ruby and httparty?</text>
+ <source>web</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>881947237</in_reply_to_status_id>
+ <in_reply_to_user_id>1000471</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 14:20:14 +0000 2008</created_at>
+ <id>881535796</id>
+ <text>@oaknd1 - delete it off phone and iTunes.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>881526234</in_reply_to_status_id>
+ <in_reply_to_user_id>3038211</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 14:07:29 +0000 2008</created_at>
+ <id>881522394</id>
+ <text>Listening to U2 "beautiful day" in honor of it being such a beautiful day.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 14:06:44 +0000 2008</created_at>
+ <id>881521592</id>
+ <text>@lizsmc1 - hi! (just passed her on the road)</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>881519558</in_reply_to_status_id>
+ <in_reply_to_user_id>11485452</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 13:59:35 +0000 2008</created_at>
+ <id>881514030</id>
+ <text>Beautiful day for a motorcycle ride.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 13:45:21 +0000 2008</created_at>
+ <id>881499439</id>
+ <text>@lizamc1 - no way! Politos will be missed. I remember eating a whole garlic pizza there with Joe.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Fri Aug 08 13:41:50 +0000 2008</created_at>
+ <id>881496024</id>
+ <text>Riding my motorcyle to campus. Using the library basement for a meeting.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 22:52:20 +0000 2008</created_at>
+ <id>880896190</id>
+ <text>Scraping super glue off my finger with a knife.</text>
+ <source>web</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 22:14:35 +0000 2008</created_at>
+ <id>880866160</id>
+ <text>So cold...Starbucks north side, you win the day, but I shall bring a sweatshirt to our next battle!</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 17:25:40 +0000 2008</created_at>
+ <id>880610064</id>
+ <text>Headed home for a bit to get my headphones and then to the north side to meet @orderedlist.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>485</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 17:15:59 +0000 2008</created_at>
+ <id>880600278</id>
+ <text>Panera wifi, why do you hate me?</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>485</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 15:46:25 +0000 2008</created_at>
+ <id>880509577</id>
+ <text>At panera. Turned my alarm off this morning and woke up late. Oh well.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>485</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 15:01:35 +0000 2008</created_at>
+ <id>880463746</id>
+ <text>@kloh I remember days like that. Exhausting. Also, NullRiver said to sync again, uninstall app from phone and then resync app. Evidently ...</text>
+ <source>web</source>
+ <truncated>true</truncated>
+ <in_reply_to_status_id>880432701</in_reply_to_status_id>
+ <in_reply_to_user_id>10193732</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>485</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 02:52:38 +0000 2008</created_at>
+ <id>879986739</id>
+ <text>@kloh - I haven't updated my OS so I'm wondering how apple could have made the app stop working. I did contact NullRiver support just no ...</text>
+ <source>web</source>
+ <truncated>true</truncated>
+ <in_reply_to_status_id>879980813</in_reply_to_status_id>
+ <in_reply_to_user_id>10193732</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 02:38:58 +0000 2008</created_at>
+ <id>879976045</id>
+ <text>@jerry - i went with the pdf download.</text>
+ <source>web</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>879878196</in_reply_to_status_id>
+ <in_reply_to_user_id>613</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 02:31:26 +0000 2008</created_at>
+ <id>879969851</id>
+ <text>@kloh - it worked at home for multiple tests and just stopped when I acyltually needed it.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id>879968483</in_reply_to_status_id>
+ <in_reply_to_user_id>10193732</in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+<status>
+ <created_at>Thu Aug 07 01:18:28 +0000 2008</created_at>
+ <id>879913748</id>
+ <text>Netshare will no longer start up for me. Of course it borks the first time I actually want to use it.</text>
+ <source>&lt;a href="http://help.twitter.com/index.php?pg=kb.page&amp;id=75"&gt;txt&lt;/a&gt;</source>
+ <truncated>false</truncated>
+ <in_reply_to_status_id></in_reply_to_status_id>
+ <in_reply_to_user_id></in_reply_to_user_id>
+ <favorited></favorited>
+ <user>
+ <id>4243</id>
+ <name>John Nunemaker</name>
+ <screen_name>jnunemaker</screen_name>
+ <location>Mishawaka, IN, US</location>
+ <description>Loves his wife, ruby, notre dame football and iu basketball</description>
+ <profile_image_url>http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg</profile_image_url>
+ <url>http://addictedtonew.com</url>
+ <protected>false</protected>
+ <followers_count>486</followers_count>
+ </user>
+</status>
+</statuses>
17 spec/happymapper_attribute_spec.rb
@@ -0,0 +1,17 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe HappyMapper::Attribute do
+ describe "initialization" do
+ before do
+ @attr = HappyMapper::Attribute.new(:foo, String)
+ end
+
+ it 'should know that it is an attribute' do
+ @attr.attribute?.should be_true
+ end
+
+ it 'should know that it is NOT an element' do
+ @attr.element?.should be_false
+ end
+ end
+end
17 spec/happymapper_element_spec.rb
@@ -0,0 +1,17 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe HappyMapper::Element do
+ describe "initialization" do
+ before do
+ @attr = HappyMapper::Element.new(:foo, String)
+ end
+
+ it 'should know that it is an element' do
+ @attr.element?.should be_true
+ end
+
+ it 'should know that it is NOT an attribute' do
+ @attr.attribute?.should be_false
+ end
+ end
+end
73 spec/happymapper_item_spec.rb
@@ -0,0 +1,73 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+describe HappyMapper::Item do
+
+ describe "new instance" do
+ before do
+ @attr = HappyMapper::Item.new(:foo, String, :xml_name => 'foobar')
+ end
+
+ it "should accept a name" do
+ @attr.name.should == 'foo'
+ end
+
+ it 'should accept a type' do
+ @attr.type.should == String
+ end
+
+ it 'should accept :xml_name as an option' do
+ @attr.xml_name.should == 'foobar'
+ end
+
+ it 'should provide #name' do
+ @attr.should respond_to(:name)
+ end
+
+ it 'should provide #type' do
+ @attr.should respond_to(:type)
+ end
+ end
+
+ describe "typecasting" do
+ it "should work with Strings" do
+ attribute = HappyMapper::Item.new(:foo, String)
+ [21, '21'].each do |a|
+ attribute.typecast(a).should == '21'
+ end
+ end
+
+ it "should work with Integers" do
+ attribute = HappyMapper::Item.new(:foo, Integer)
+ [21, 21.0, '21'].each do |a|
+ attribute.typecast(a).should == 21
+ end
+ end
+
+ it "should work with Floats" do
+ attribute = HappyMapper::Item.new(:foo, Float)
+ [21, 21.0, '21'].each do |a|
+ attribute.typecast(a).should == 21.0
+ end
+ end
+
+ it "should work with Times" do
+ attribute = HappyMapper::Item.new(:foo, Time)
+ attribute.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
+ end
+
+ it "should work with Dates" do
+ attribute = HappyMapper::Item.new(:foo, Date)
+ attribute.typecast('2000-01-01').should == Date.new(2000, 1, 1)
+ end
+
+ it "should work with DateTimes" do
+ attribute = HappyMapper::Item.new(:foo, DateTime)
+ attribute.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
+ end
+
+ it "should work with Boolean" do
+ attribute = HappyMapper::Item.new(:foo, Boolean)
+ attribute.typecast('false').should == false
+ end
+ end
+end
125 spec/happymapper_spec.rb
@@ -0,0 +1,125 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+
+class Post
+ include HappyMapper
+
+ attribute :href, String
+ attribute :hash, String
+ attribute :description, String
+ attribute :tag, String
+ attribute :time, Time
+ attribute :others, Integer
+ attribute :extended, String
+end
+
+class Status
+ include HappyMapper
+
+ element :id, Integer
+ element :text, String
+ element :created_at, Time
+ element :source, String
+ element :truncated, Boolean
+ element :in_reply_to_status_id, Integer
+ element :in_reply_to_user_id, Integer
+ element :favorited, Boolean
+end
+describe HappyMapper do
+
+ describe "being included into another class" do
+ class Foo; include HappyMapper end
+
+ it "should set @attributes to a hash" do
+ Foo.instance_variable_get("@attributes").should == {}
+ end
+
+ it "should set @elements to a hash" do
+ Foo.instance_variable_get("@elements").should == {}
+ end
+
+ it "should provide #attribute" do
+ Foo.should respond_to(:attribute)
+ end
+
+ it "should provide #attributes" do
+ Foo.should respond_to(:attributes)
+ end
+
+ it "should provide #element" do
+ Foo.should respond_to(:element)
+ end
+
+ it "should provide #elements" do
+ Foo.should respond_to(:elements)
+ end
+
+ it "should default tag_name to class" do
+ Foo.get_tag_name.should == 'foo'
+ end
+
+ it "should allow setting tag_name" do
+ Foo.tag_name('FooBar')
+ Foo.get_tag_name.should == 'FooBar'
+ end
+
+ it "should provide #parse" do
+ Foo.should respond_to(:parse)
+ end
+ end
+
+ describe "#attributes" do
+ it "should only return attributes for the current class" do
+ Post.attributes.size.should == 7
+ Status.attributes.size.should == 0
+ end
+ end
+
+ describe "#elements" do
+ it "should only return elements for the current class" do
+ Post.elements.size.should == 0
+ Status.elements.size.should == 8
+ end
+ end
+
+ describe "#parse (with attribute heavy xml)" do
+ before do
+ @posts = Post.parse(File.read(File.dirname(__FILE__) + '/fixtures/posts.xml'))
+ end
+
+ it "should get the correct number of elements" do
+ @posts.size.should == 20
+ end
+
+ it "should properly assign attributes" do
+ first = @posts.first
+ first.href.should == 'http://roxml.rubyforge.org/'
+ first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
+ first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
+ first.tag.should == 'ruby xml gems mapping'
+ first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
+ first.others.should == 56
+ first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.'
+ end
+ end
+
+ describe "#parse (with element heavy xml)" do
+ before do
+ @statuses = Status.parse(File.read(File.dirname(__FILE__) + '/fixtures/statuses.xml'))
+ end
+
+ it "should get the correct number of elements" do
+ @statuses.size.should == 20
+ end
+
+ it "should properly assign attributes" do
+ first = @statuses.first
+ first.id.should == 882281424
+ first.created_at.should == Time.mktime(2008, 8, 9, 1, 38, 12)
+ first.source.should == 'web'
+ first.truncated.should == false
+ first.in_reply_to_status_id.should == 1234
+ first.in_reply_to_user_id.should == 12345
+ first.favorited.should == false
+ end
+ end
+end
1 spec/spec.opts
@@ -0,0 +1 @@
+--colour
9 spec/spec_helper.rb
@@ -0,0 +1,9 @@
+begin
+ require 'spec'
+rescue LoadError
+ require 'rubygems'
+ gem 'rspec'
+ require 'spec'
+end
+
+require File.join(File.dirname(__FILE__), '..', 'lib', 'happymapper')
34 tasks/deployment.rake
@@ -0,0 +1,34 @@
+desc 'Release the website and new gem version'
+task :deploy => [:check_version, :website, :release] do
+ puts "Remember to create SVN tag:"
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
+ puts "Suggested comment:"
+ puts "Tagging release #{CHANGES}"
+end
+
+desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
+task :local_deploy => [:website_generate, :install_gem]
+
+task :check_version do
+ unless ENV['VERSION']
+ puts 'Must pass a VERSION=x.y.z release version'
+ exit
+ end
+ unless ENV['VERSION'] == VERS
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
+ exit
+ end
+end
+
+desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
+task :install_gem_no_doc => [:clean, :package] do
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
+end
+
+namespace :manifest do
+ desc 'Recreate Manifest.txt to include ALL files'
+ task :refresh do
+ `rake check_manifest | patch -p0 > Manifest.txt`
+ end
+end
7 tasks/environment.rake
@@ -0,0 +1,7 @@
+task :ruby_env do
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
+ "jruby"
+ else
+ "ruby"
+ end unless defined? RUBY_APP
+end
21 tasks/rspec.rake
@@ -0,0 +1,21 @@
+begin
+ require 'spec'
+rescue LoadError
+ require 'rubygems'
+ require 'spec'
+end
+begin
+ require 'spec/rake/spectask'
+rescue LoadError
+ puts <<-EOS
+To use rspec for testing you must install rspec gem:
+ gem install rspec
+EOS
+ exit(0)
+end
+
+desc "Run the specs under spec/models"
+Spec::Rake::SpecTask.new do |t|
+ t.spec_opts = ['--options', "spec/spec.opts"]
+ t.spec_files = FileList['spec/**/*_spec.rb']
+end
17 tasks/website.rake
@@ -0,0 +1,17 @@
+desc 'Generate website files'
+task :website_generate => :ruby_env do
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
+ end
+end
+
+desc 'Upload website files to rubyforge'
+task :website_upload do
+ host = "#{rubyforge_username}@rubyforge.org"
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
+ local_dir = 'website'
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
+end
+
+desc 'Generate and upload website files'
+task :website => [:website_generate, :website_upload, :publish_docs]
11 website/index.html
@@ -0,0 +1,11 @@
+<html>
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8">
+ <title>happymapper</title>
+
+ </head>
+ <body id="body">
+ <p>This page has not yet been created for RubyGem <code>happymapper</code></p>
+ <p>To the developer: To generate it, update website/index.txt and run the rake task <code>website</code> to generate this <code>index.html</code> file.</p>
+ </body>
+</html>
0 website/index.txt
No changes.
285 website/javascripts/rounded_corners_lite.inc.js
@@ -0,0 +1,285 @@
+
+ /****************************************************************
+ * *
+ * curvyCorners *
+ * ------------ *
+ * *
+ * This script generates rounded corners for your divs. *
+ * *
+ * Version 1.2.9 *
+ * Copyright (c) 2006 Cameron Cooke *
+ * By: Cameron Cooke and Tim Hutchison. *
+ * *
+ * *
+ * Website: http://www.curvycorners.net *
+ * Email: info@totalinfinity.com *
+ * Forum: http://www.curvycorners.net/forum/ *
+ * *
+ * *
+ * This library is free software; you can redistribute *
+ * it and/or modify it under the terms of the GNU *
+ * Lesser General Public License as published by the *
+ * Free Software Foundation; either version 2.1 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * This library is distributed in the hope that it will *
+ * be useful, but WITHOUT ANY WARRANTY; without even the *
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A *
+ * PARTICULAR PURPOSE. See the GNU Lesser General Public *
+ * License for more details. *
+ * *
+ * You should have received a copy of the GNU Lesser *
+ * General Public License along with this library; *
+ * Inc., 59 Temple Place, Suite 330, Boston, *
+ * MA 02111-1307 USA *
+ * *
+ ****************************************************************/
+
+var isIE = navigator.userAgent.toLowerCase().indexOf("msie") > -1; var isMoz = document.implementation && document.implementation.createDocument; var isSafari = ((navigator.userAgent.toLowerCase().indexOf('safari')!=-1)&&(navigator.userAgent.toLowerCase().indexOf('mac')!=-1))?true:false; function curvyCorners()
+{ if(typeof(arguments[0]) != "object") throw newCurvyError("First parameter of curvyCorners() must be an object."); if(typeof(arguments[1]) != "object" && typeof(arguments[1]) != "string") throw newCurvyError("Second parameter of curvyCorners() must be an object or a class name."); if(typeof(arguments[1]) == "string")
+{ var startIndex = 0; var boxCol = getElementsByClass(arguments[1]);}
+else
+{ var startIndex = 1; var boxCol = arguments;}
+var curvyCornersCol = new Array(); if(arguments[0].validTags)
+var validElements = arguments[0].validTags; else
+var validElements = ["div"]; for(var i = startIndex, j = boxCol.length; i < j; i++)
+{ var currentTag = boxCol[i].tagName.toLowerCase(); if(inArray(validElements, currentTag) !== false)
+{ curvyCornersCol[curvyCornersCol.length] = new curvyObject(arguments[0], boxCol[i]);}
+}
+this.objects = curvyCornersCol; this.applyCornersToAll = function()
+{ for(var x = 0, k = this.objects.length; x < k; x++)
+{ this.objects[x].applyCorners();}
+}
+}
+function curvyObject()
+{ this.box = arguments[1]; this.settings = arguments[0]; this.topContainer = null; this.bottomContainer = null; this.masterCorners = new Array(); this.contentDIV = null; var boxHeight = get_style(this.box, "height", "height"); var boxWidth = get_style(this.box, "width", "width"); var borderWidth = get_style(this.box, "borderTopWidth", "border-top-width"); var borderColour = get_style(this.box, "borderTopColor", "border-top-color"); var boxColour = get_style(this.box, "backgroundColor", "background-color"); var backgroundImage = get_style(this.box, "backgroundImage", "background-image"); var boxPosition = get_style(this.box, "position", "position"); var boxPadding = get_style(this.box, "paddingTop", "padding-top"); this.boxHeight = parseInt(((boxHeight != "" && boxHeight != "auto" && boxHeight.indexOf("%") == -1)? boxHeight.substring(0, boxHeight.indexOf("px")) : this.box.scrollHeight)); this.boxWidth = parseInt(((boxWidth != "" && boxWidth != "auto" && boxWidth.indexOf("%") == -1)? boxWidth.substring(0, boxWidth.indexOf("px")) : this.box.scrollWidth)); this.borderWidth = parseInt(((borderWidth != "" && borderWidth.indexOf("px") !== -1)? borderWidth.slice(0, borderWidth.indexOf("px")) : 0)); this.boxColour = format_colour(boxColour); this.boxPadding = parseInt(((boxPadding != "" && boxPadding.indexOf("px") !== -1)? boxPadding.slice(0, boxPadding.indexOf("px")) : 0)); this.borderColour = format_colour(borderColour); this.borderString = this.borderWidth + "px" + " solid " + this.borderColour; this.backgroundImage = ((backgroundImage != "none")? backgroundImage : ""); this.boxContent = this.box.innerHTML; if(boxPosition != "absolute") this.box.style.position = "relative"; this.box.style.padding = "0px"; if(isIE && boxWidth == "auto" && boxHeight == "auto") this.box.style.width = "100%"; if(this.settings.autoPad == true && this.boxPadding > 0)
+this.box.innerHTML = ""; this.applyCorners = function()
+{ for(var t = 0; t < 2; t++)
+{ switch(t)
+{ case 0:
+if(this.settings.tl || this.settings.tr)
+{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var topMaxRadius = Math.max(this.settings.tl ? this.settings.tl.radius : 0, this.settings.tr ? this.settings.tr.radius : 0); newMainContainer.style.height = topMaxRadius + "px"; newMainContainer.style.top = 0 - topMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.topContainer = this.box.appendChild(newMainContainer);}
+break; case 1:
+if(this.settings.bl || this.settings.br)
+{ var newMainContainer = document.createElement("DIV"); newMainContainer.style.width = "100%"; newMainContainer.style.fontSize = "1px"; newMainContainer.style.overflow = "hidden"; newMainContainer.style.position = "absolute"; newMainContainer.style.paddingLeft = this.borderWidth + "px"; newMainContainer.style.paddingRight = this.borderWidth + "px"; var botMaxRadius = Math.max(this.settings.bl ? this.settings.bl.radius : 0, this.settings.br ? this.settings.br.radius : 0); newMainContainer.style.height = botMaxRadius + "px"; newMainContainer.style.bottom = 0 - botMaxRadius + "px"; newMainContainer.style.left = 0 - this.borderWidth + "px"; this.bottomContainer = this.box.appendChild(newMainContainer);}
+break;}
+}
+if(this.topContainer) this.box.style.borderTopWidth = "0px"; if(this.bottomContainer) this.box.style.borderBottomWidth = "0px"; var corners = ["tr", "tl", "br", "bl"]; for(var i in corners)
+{ if(i > -1 < 4)
+{ var cc = corners[i]; if(!this.settings[cc])
+{ if(((cc == "tr" || cc == "tl") && this.topContainer != null) || ((cc == "br" || cc == "bl") && this.bottomContainer != null))
+{ var newCorner = document.createElement("DIV"); newCorner.style.position = "relative"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; if(this.backgroundImage == "")
+newCorner.style.backgroundColor = this.boxColour; else
+newCorner.style.backgroundImage = this.backgroundImage; switch(cc)
+{ case "tl":
+newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.tr.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.left = -this.borderWidth + "px"; break; case "tr":
+newCorner.style.height = topMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.tl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderTop = this.borderString; newCorner.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; newCorner.style.left = this.borderWidth + "px"; break; case "bl":
+newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginRight = this.settings.br.radius - (this.borderWidth*2) + "px"; newCorner.style.borderLeft = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = -this.borderWidth + "px"; newCorner.style.backgroundPosition = "-" + (this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break; case "br":
+newCorner.style.height = botMaxRadius - this.borderWidth + "px"; newCorner.style.marginLeft = this.settings.bl.radius - (this.borderWidth*2) + "px"; newCorner.style.borderRight = this.borderString; newCorner.style.borderBottom = this.borderString; newCorner.style.left = this.borderWidth + "px"
+newCorner.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (botMaxRadius + this.borderWidth)) + "px"; break;}
+}
+}
+else
+{ if(this.masterCorners[this.settings[cc].radius])
+{ var newCorner = this.masterCorners[this.settings[cc].radius].cloneNode(true);}
+else
+{ var newCorner = document.createElement("DIV"); newCorner.style.height = this.settings[cc].radius + "px"; newCorner.style.width = this.settings[cc].radius + "px"; newCorner.style.position = "absolute"; newCorner.style.fontSize = "1px"; newCorner.style.overflow = "hidden"; var borderRadius = parseInt(this.settings[cc].radius - this.borderWidth); for(var intx = 0, j = this.settings[cc].radius; intx < j; intx++)
+{ if((intx +1) >= borderRadius)
+var y1 = -1; else
+var y1 = (Math.floor(Math.sqrt(Math.pow(borderRadius, 2) - Math.pow((intx+1), 2))) - 1); if(borderRadius != j)
+{ if((intx) >= borderRadius)
+var y2 = -1; else
+var y2 = Math.ceil(Math.sqrt(Math.pow(borderRadius,2) - Math.pow(intx, 2))); if((intx+1) >= j)
+var y3 = -1; else
+var y3 = (Math.floor(Math.sqrt(Math.pow(j ,2) - Math.pow((intx+1), 2))) - 1);}
+if((intx) >= j)
+var y4 = -1; else
+var y4 = Math.ceil(Math.sqrt(Math.pow(j ,2) - Math.pow(intx, 2))); if(y1 > -1) this.drawPixel(intx, 0, this.boxColour, 100, (y1+1), newCorner, -1, this.settings[cc].radius); if(borderRadius != j)
+{ for(var inty = (y1 + 1); inty < y2; inty++)
+{ if(this.settings.antiAlias)
+{ if(this.backgroundImage != "")
+{ var borderFract = (pixelFraction(intx, inty, borderRadius) * 100); if(borderFract < 30)
+{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, 0, this.settings[cc].radius);}
+else
+{ this.drawPixel(intx, inty, this.borderColour, 100, 1, newCorner, -1, this.settings[cc].radius);}
+}
+else
+{ var pixelcolour = BlendColour(this.boxColour, this.borderColour, pixelFraction(intx, inty, borderRadius)); this.drawPixel(intx, inty, pixelcolour, 100, 1, newCorner, 0, this.settings[cc].radius, cc);}
+}
+}
+if(this.settings.antiAlias)
+{ if(y3 >= y2)
+{ if (y2 == -1) y2 = 0; this.drawPixel(intx, y2, this.borderColour, 100, (y3 - y2 + 1), newCorner, 0, 0);}
+}
+else
+{ if(y3 >= y1)
+{ this.drawPixel(intx, (y1 + 1), this.borderColour, 100, (y3 - y1), newCorner, 0, 0);}
+}
+var outsideColour = this.borderColour;}
+else
+{ var outsideColour = this.boxColour; var y3 = y1;}
+if(this.settings.antiAlias)
+{ for(var inty = (y3 + 1); inty < y4; inty++)
+{ this.drawPixel(intx, inty, outsideColour, (pixelFraction(intx, inty , j) * 100), 1, newCorner, ((this.borderWidth > 0)? 0 : -1), this.settings[cc].radius);}
+}
+}
+this.masterCorners[this.settings[cc].radius] = newCorner.cloneNode(true);}
+if(cc != "br")
+{ for(var t = 0, k = newCorner.childNodes.length; t < k; t++)
+{ var pixelBar = newCorner.childNodes[t]; var pixelBarTop = parseInt(pixelBar.style.top.substring(0, pixelBar.style.top.indexOf("px"))); var pixelBarLeft = parseInt(pixelBar.style.left.substring(0, pixelBar.style.left.indexOf("px"))); var pixelBarHeight = parseInt(pixelBar.style.height.substring(0, pixelBar.style.height.indexOf("px"))); if(cc == "tl" || cc == "bl"){ pixelBar.style.left = this.settings[cc].radius -pixelBarLeft -1 + "px";}
+if(cc == "tr" || cc == "tl"){ pixelBar.style.top = this.settings[cc].radius -pixelBarHeight -pixelBarTop + "px";}
+switch(cc)
+{ case "tr":
+pixelBar.style.backgroundPosition = "-" + Math.abs((this.boxWidth - this.settings[cc].radius + this.borderWidth) + pixelBarLeft) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "tl":
+pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs(this.settings[cc].radius -pixelBarHeight -pixelBarTop - this.borderWidth) + "px"; break; case "bl":
+pixelBar.style.backgroundPosition = "-" + Math.abs((this.settings[cc].radius -pixelBarLeft -1) - this.borderWidth) + "px -" + Math.abs((this.boxHeight + this.settings[cc].radius + pixelBarTop) -this.borderWidth) + "px"; break;}
+}
+}
+}
+if(newCorner)
+{ switch(cc)
+{ case "tl":
+if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "tr":
+if(newCorner.style.position == "absolute") newCorner.style.top = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.topContainer) this.topContainer.appendChild(newCorner); break; case "bl":
+if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.left = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break; case "br":
+if(newCorner.style.position == "absolute") newCorner.style.bottom = "0px"; if(newCorner.style.position == "absolute") newCorner.style.right = "0px"; if(this.bottomContainer) this.bottomContainer.appendChild(newCorner); break;}
+}
+}
+}
+var radiusDiff = new Array(); radiusDiff["t"] = Math.abs(this.settings.tl.radius - this.settings.tr.radius)
+radiusDiff["b"] = Math.abs(this.settings.bl.radius - this.settings.br.radius); for(z in radiusDiff)
+{ if(z == "t" || z == "b")
+{ if(radiusDiff[z])
+{ var smallerCornerType = ((this.settings[z + "l"].radius < this.settings[z + "r"].radius)? z +"l" : z +"r"); var newFiller = document.createElement("DIV"); newFiller.style.height = radiusDiff[z] + "px"; newFiller.style.width = this.settings[smallerCornerType].radius+ "px"
+newFiller.style.position = "absolute"; newFiller.style.fontSize = "1px"; newFiller.style.overflow = "hidden"; newFiller.style.backgroundColor = this.boxColour; switch(smallerCornerType)
+{ case "tl":
+newFiller.style.bottom = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.topContainer.appendChild(newFiller); break; case "tr":
+newFiller.style.bottom = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.topContainer.appendChild(newFiller); break; case "bl":
+newFiller.style.top = "0px"; newFiller.style.left = "0px"; newFiller.style.borderLeft = this.borderString; this.bottomContainer.appendChild(newFiller); break; case "br":
+newFiller.style.top = "0px"; newFiller.style.right = "0px"; newFiller.style.borderRight = this.borderString; this.bottomContainer.appendChild(newFiller); break;}
+}
+var newFillerBar = document.createElement("DIV"); newFillerBar.style.position = "relative"; newFillerBar.style.fontSize = "1px"; newFillerBar.style.overflow = "hidden"; newFillerBar.style.backgroundColor = this.boxColour; newFillerBar.style.backgroundImage = this.backgroundImage; switch(z)
+{ case "t":
+if(this.topContainer)
+{ if(this.settings.tl.radius && this.settings.tr.radius)
+{ newFillerBar.style.height = topMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.tl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.tr.radius - this.borderWidth + "px"; newFillerBar.style.borderTop = this.borderString; if(this.backgroundImage != "")
+newFillerBar.style.backgroundPosition = "-" + (topMaxRadius + this.borderWidth) + "px 0px"; this.topContainer.appendChild(newFillerBar);}
+this.box.style.backgroundPosition = "0px -" + (topMaxRadius - this.borderWidth) + "px";}
+break; case "b":
+if(this.bottomContainer)
+{ if(this.settings.bl.radius && this.settings.br.radius)
+{ newFillerBar.style.height = botMaxRadius - this.borderWidth + "px"; newFillerBar.style.marginLeft = this.settings.bl.radius - this.borderWidth + "px"; newFillerBar.style.marginRight = this.settings.br.radius - this.borderWidth + "px"; newFillerBar.style.borderBottom = this.borderString; if(this.backgroundImage != "")
+newFillerBar.style.backgroundPosition = "-" + (botMaxRadius + this.borderWidth) + "px -" + (this.boxHeight + (topMaxRadius + this.borderWidth)) + "px"; this.bottomContainer.appendChild(newFillerBar);}
+}
+break;}
+}
+}
+if(this.settings.autoPad == true && this.boxPadding > 0)
+{ var contentContainer = document.createElement("DIV"); contentContainer.style.position = "relative"; contentContainer.innerHTML = this.boxContent; contentContainer.className = "autoPadDiv"; var topPadding = Math.abs(topMaxRadius - this.boxPadding); var botPadding = Math.abs(botMaxRadius - this.boxPadding); if(topMaxRadius < this.boxPadding)
+contentContainer.style.paddingTop = topPadding + "px"; if(botMaxRadius < this.boxPadding)
+contentContainer.style.paddingBottom = botMaxRadius + "px"; contentContainer.style.paddingLeft = this.boxPadding + "px"; contentContainer.style.paddingRight = this.boxPadding + "px"; this.contentDIV = this.box.appendChild(contentContainer);}
+}
+this.drawPixel = function(intx, inty, colour, transAmount, height, newCorner, image, cornerRadius)
+{ var pixel = document.createElement("DIV"); pixel.style.height = height + "px"; pixel.style.width = "1px"; pixel.style.position = "absolute"; pixel.style.fontSize = "1px"; pixel.style.overflow = "hidden"; var topMaxRadius = Math.max(this.settings["tr"].radius, this.settings["tl"].radius); if(image == -1 && this.backgroundImage != "")
+{ pixel.style.backgroundImage = this.backgroundImage; pixel.style.backgroundPosition = "-" + (this.boxWidth - (cornerRadius - intx) + this.borderWidth) + "px -" + ((this.boxHeight + topMaxRadius + inty) -this.borderWidth) + "px";}
+else
+{ pixel.style.backgroundColor = colour;}
+if (transAmount != 100)
+setOpacity(pixel, transAmount); pixel.style.top = inty + "px"; pixel.style.left = intx + "px"; newCorner.appendChild(pixel);}
+}
+function insertAfter(parent, node, referenceNode)
+{ parent.insertBefore(node, referenceNode.nextSibling);}
+function BlendColour(Col1, Col2, Col1Fraction)
+{ var red1 = parseInt(Col1.substr(1,2),16); var green1 = parseInt(Col1.substr(3,2),16); var blue1 = parseInt(Col1.substr(5,2),16); var red2 = parseInt(Col2.substr(1,2),16); var green2 = parseInt(Col2.substr(3,2),16); var blue2 = parseInt(Col2.substr(5,2),16); if(Col1Fraction > 1 || Col1Fraction < 0) Col1Fraction = 1; var endRed = Math.round((red1 * Col1Fraction) + (red2 * (1 - Col1Fraction))); if(endRed > 255) endRed = 255; if(endRed < 0) endRed = 0; var endGreen = Math.round((green1 * Col1Fraction) + (green2 * (1 - Col1Fraction))); if(endGreen > 255) endGreen = 255; if(endGreen < 0) endGreen = 0; var endBlue = Math.round((blue1 * Col1Fraction) + (blue2 * (1 - Col1Fraction))); if(endBlue > 255) endBlue = 255; if(endBlue < 0) endBlue = 0; return "#" + IntToHex(endRed)+ IntToHex(endGreen)+ IntToHex(endBlue);}
+function IntToHex(strNum)
+{ base = strNum / 16; rem = strNum % 16; base = base - (rem / 16); baseS = MakeHex(base); remS = MakeHex(rem); return baseS + '' + remS;}
+function MakeHex(x)
+{ if((x >= 0) && (x <= 9))
+{ return x;}
+else
+{ switch(x)
+{ case 10: return "A"; case 11: return "B"; case 12: return "C"; case 13: return "D"; case 14: return "E"; case 15: return "F";}
+}
+}
+function pixelFraction(x, y, r)
+{ var pixelfraction = 0; var xvalues = new Array(1); var yvalues = new Array(1); var point = 0; var whatsides = ""; var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x,2))); if ((intersect >= y) && (intersect < (y+1)))
+{ whatsides = "Left"; xvalues[point] = 0; yvalues[point] = intersect - y; point = point + 1;}
+var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y+1,2))); if ((intersect >= x) && (intersect < (x+1)))
+{ whatsides = whatsides + "Top"; xvalues[point] = intersect - x; yvalues[point] = 1; point = point + 1;}
+var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(x+1,2))); if ((intersect >= y) && (intersect < (y+1)))
+{ whatsides = whatsides + "Right"; xvalues[point] = 1; yvalues[point] = intersect - y; point = point + 1;}
+var intersect = Math.sqrt((Math.pow(r,2) - Math.pow(y,2))); if ((intersect >= x) && (intersect < (x+1)))
+{ whatsides = whatsides + "Bottom"; xvalues[point] = intersect - x; yvalues[point] = 0;}
+switch (whatsides)
+{ case "LeftRight":
+pixelfraction = Math.min(yvalues[0],yvalues[1]) + ((Math.max(yvalues[0],yvalues[1]) - Math.min(yvalues[0],yvalues[1]))/2); break; case "TopRight":
+pixelfraction = 1-(((1-xvalues[0])*(1-yvalues[1]))/2); break; case "TopBottom":
+pixelfraction = Math.min(xvalues[0],xvalues[1]) + ((Math.max(xvalues[0],xvalues[1]) - Math.min(xvalues[0],xvalues[1]))/2); break; case "LeftBottom":
+pixelfraction = (yvalues[0]*xvalues[1])/2; break; default:
+pixelfraction = 1;}
+return pixelfraction;}
+function rgb2Hex(rgbColour)
+{ try{ var rgbArray = rgb2Array(rgbColour); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); var hexColour = "#" + IntToHex(red) + IntToHex(green) + IntToHex(blue);}
+catch(e){ alert("There was an error converting the RGB value to Hexadecimal in function rgb2Hex");}
+return hexColour;}
+function rgb2Array(rgbColour)
+{ var rgbValues = rgbColour.substring(4, rgbColour.indexOf(")")); var rgbArray = rgbValues.split(", "); return rgbArray;}
+function setOpacity(obj, opacity)
+{ opacity = (opacity == 100)?99.999:opacity; if(isSafari && obj.tagName != "IFRAME")
+{ var rgbArray = rgb2Array(obj.style.backgroundColor); var red = parseInt(rgbArray[0]); var green = parseInt(rgbArray[1]); var blue = parseInt(rgbArray[2]); obj.style.backgroundColor = "rgba(" + red + ", " + green + ", " + blue + ", " + opacity/100 + ")";}
+else if(typeof(obj.style.opacity) != "undefined")
+{ obj.style.opacity = opacity/100;}
+else if(typeof(obj.style.MozOpacity) != "undefined")
+{ obj.style.MozOpacity = opacity/100;}
+else if(typeof(obj.style.filter) != "undefined")
+{ obj.style.filter = "alpha(opacity:" + opacity + ")";}
+else if(typeof(obj.style.KHTMLOpacity) != "undefined")
+{ obj.style.KHTMLOpacity = opacity/100;}
+}
+function inArray(array, value)
+{ for(var i = 0; i < array.length; i++){ if (array[i] === value) return i;}
+return false;}
+function inArrayKey(array, value)
+{ for(key in array){ if(key === value) return true;}
+return false;}
+function addEvent(elm, evType, fn, useCapture) { if (elm.addEventListener) { elm.addEventListener(evType, fn, useCapture); return true;}
+else if (elm.attachEvent) { var r = elm.attachEvent('on' + evType, fn); return r;}
+else { elm['on' + evType] = fn;}
+}
+function removeEvent(obj, evType, fn, useCapture){ if (obj.removeEventListener){ obj.removeEventListener(evType, fn, useCapture); return true;} else if (obj.detachEvent){ var r = obj.detachEvent("on"+evType, fn); return r;} else { alert("Handler could not be removed");}
+}
+function format_colour(colour)
+{ var returnColour = "#ffffff"; if(colour != "" && colour != "transparent")
+{ if(colour.substr(0, 3) == "rgb")
+{ returnColour = rgb2Hex(colour);}
+else if(colour.length == 4)
+{ returnColour = "#" + colour.substring(1, 2) + colour.substring(1, 2) + colour.substring(2, 3) + colour.substring(2, 3) + colour.substring(3, 4) + colour.substring(3, 4);}
+else
+{ returnColour = colour;}
+}
+return returnColour;}
+function get_style(obj, property, propertyNS)
+{ try
+{ if(obj.currentStyle)
+{ var returnVal = eval("obj.currentStyle." + property);}
+else
+{ if(isSafari && obj.style.display == "none")
+{ obj.style.display = ""; var wasHidden = true;}
+var returnVal = document.defaultView.getComputedStyle(obj, '').getPropertyValue(propertyNS); if(isSafari && wasHidden)
+{ obj.style.display = "none";}
+}
+}
+catch(e)
+{ }
+return returnVal;}
+function getElementsByClass(searchClass, node, tag)
+{ var classElements = new Array(); if(node == null)
+node = document; if(tag == null)
+tag = '*'; var els = node.getElementsByTagName(tag); var elsLen = els.length; var pattern = new RegExp("(^|\s)"+searchClass+"(\s|$)"); for (i = 0, j = 0; i < elsLen; i++)
+{ if(pattern.test(els[i].className))
+{ classElements[j] = els[i]; j++;}
+}
+return classElements;}
+function newCurvyError(errorMessage)
+{ return new Error("curvyCorners Error:\n" + errorMessage)
+}
138 website/stylesheets/screen.css
@@ -0,0 +1,138 @@
+body {
+ background-color: #E1D1F1;
+ font-family: "Georgia", sans-serif;
+ font-size: 16px;
+ line-height: 1.6em;
+ padding: 1.6em 0 0 0;
+ color: #333;
+}
+h1, h2, h3, h4, h5, h6 {
+ color: #444;
+}
+h1 {
+ font-family: sans-serif;
+ font-weight: normal;
+ font-size: 4em;
+ line-height: 0.8em;
+ letter-spacing: -0.1ex;
+ margin: 5px;
+}
+li {
+ padding: 0;
+ margin: 0;
+ list-style-type: square;
+}
+a {
+ color: #5E5AFF;
+ background-color: #DAC;
+ font-weight: normal;
+ text-decoration: underline;
+}
+blockquote {
+ font-size: 90%;
+ font-style: italic;
+ border-left: 1px solid #111;
+ padding-left: 1em;
+}
+.caps {
+ font-size: 80%;
+}
+
+#main {
+ width: 45em;
+ padding: 0;
+ margin: 0 auto;
+}
+.coda {
+ text-align: right;
+ color: #77f;
+ font-size: smaller;
+}
+
+table {
+ font-size: 90%;
+ line-height: 1.4em;
+ color: #ff8;
+ background-color: #111;
+ padding: 2px 10px 2px 10px;
+ border-style: dashed;
+}
+
+th {
+ color: #fff;
+}
+
+td {
+ padding: 2px 10px 2px 10px;
+}
+
+.success {
+ color: #0CC52B;
+}
+
+.failed {
+ color: #E90A1B;
+}
+
+.unknown {
+ color: #995000;
+}
+pre, code {
+ font-family: monospace;
+ font-size: 90%;
+ line-height: 1.4em;
+ color: #ff8;
+ background-color: #111;
+ padding: 2px 10px 2px 10px;
+}
+.comment { color: #aaa; font-style: italic; }
+.keyword { color: #eff; font-weight: bold; }
+.punct { color: #eee; font-weight: bold; }
+.symbol { color: #0bb; }
+.string { color: #6b4; }
+.ident { color: #ff8; }
+.constant { color: #66f; }
+.regex { color: #ec6; }
+.number { color: #F99; }
+.expr { color: #227; }
+
+#version {
+ float: right;
+ text-align: right;
+ font-family: sans-serif;
+ font-weight: normal;
+ background-color: #B3ABFF;
+ color: #141331;
+ padding: 15px 20px 10px 20px;
+ margin: 0 auto;
+ margin-top: 15px;
+ border: 3px solid #141331;
+}
+
+#version .numbers {
+ display: block;
+ font-size: 4em;
+ line-height: 0.8em;
+ letter-spacing: -0.1ex;
+ margin-bottom: 15px;
+}
+
+#version p {
+ text-decoration: none;
+ color: #141331;
+ background-color: #B3ABFF;
+ margin: 0;
+ padding: 0;
+}
+
+#version a {
+ text-decoration: none;
+ color: #141331;
+ background-color: #B3ABFF;
+}
+
+.clickable {
+ cursor: pointer;
+ cursor: hand;
+}
+
0 website/template.html.erb
No changes.

0 comments on commit 9d8c631

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