happymapper 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe HappyMapper::Attribute do
4
+ describe "initialization" do
5
+ before do
6
+ @attr = HappyMapper::Attribute.new(:foo, String)
7
+ end
8
+
9
+ it 'should know that it is an attribute' do
10
+ @attr.attribute?.should be_true
11
+ end
12
+
13
+ it 'should know that it is NOT an element' do
14
+ @attr.element?.should be_false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe HappyMapper::Element do
4
+ describe "initialization" do
5
+ before do
6
+ @attr = HappyMapper::Element.new(:foo, String)
7
+ end
8
+
9
+ it 'should know that it is an element' do
10
+ @attr.element?.should be_true
11
+ end
12
+
13
+ it 'should know that it is NOT an attribute' do
14
+ @attr.attribute?.should be_false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,73 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe HappyMapper::Item do
4
+
5
+ describe "new instance" do
6
+ before do
7
+ @attr = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
8
+ end
9
+
10
+ it "should accept a name" do
11
+ @attr.name.should == 'foo'
12
+ end
13
+
14
+ it 'should accept a type' do
15
+ @attr.type.should == String
16
+ end
17
+
18
+ it 'should accept :tag as an option' do
19
+ @attr.tag.should == 'foobar'
20
+ end
21
+
22
+ it 'should provide #name' do
23
+ @attr.should respond_to(:name)
24
+ end
25
+
26
+ it 'should provide #type' do
27
+ @attr.should respond_to(:type)
28
+ end
29
+ end
30
+
31
+ describe "typecasting" do
32
+ it "should work with Strings" do
33
+ attribute = HappyMapper::Item.new(:foo, String)
34
+ [21, '21'].each do |a|
35
+ attribute.typecast(a).should == '21'
36
+ end
37
+ end
38
+
39
+ it "should work with Integers" do
40
+ attribute = HappyMapper::Item.new(:foo, Integer)
41
+ [21, 21.0, '21'].each do |a|
42
+ attribute.typecast(a).should == 21
43
+ end
44
+ end
45
+
46
+ it "should work with Floats" do
47
+ attribute = HappyMapper::Item.new(:foo, Float)
48
+ [21, 21.0, '21'].each do |a|
49
+ attribute.typecast(a).should == 21.0
50
+ end
51
+ end
52
+
53
+ it "should work with Times" do
54
+ attribute = HappyMapper::Item.new(:foo, Time)
55
+ attribute.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
56
+ end
57
+
58
+ it "should work with Dates" do
59
+ attribute = HappyMapper::Item.new(:foo, Date)
60
+ attribute.typecast('2000-01-01').should == Date.new(2000, 1, 1)
61
+ end
62
+
63
+ it "should work with DateTimes" do
64
+ attribute = HappyMapper::Item.new(:foo, DateTime)
65
+ attribute.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
66
+ end
67
+
68
+ it "should work with Boolean" do
69
+ attribute = HappyMapper::Item.new(:foo, Boolean)
70
+ attribute.typecast('false').should == false
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,213 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ class Post
4
+ include HappyMapper
5
+
6
+ attribute :href, String
7
+ attribute :hash, String
8
+ attribute :description, String
9
+ attribute :tag, String
10
+ attribute :time, Time
11
+ attribute :others, Integer
12
+ attribute :extended, String
13
+ end
14
+
15
+ class User
16
+ include HappyMapper
17
+
18
+ element :id, Integer
19
+ element :name, String
20
+ element :screen_name, String
21
+ element :location, String
22
+ element :description, String
23
+ element :profile_image_url, String
24
+ element :url, String
25
+ element :protected, Boolean
26
+ element :followers_count, Integer
27
+ end
28
+
29
+ class Status
30
+ include HappyMapper
31
+
32
+ element :id, Integer
33
+ element :text, String
34
+ element :created_at, Time
35
+ element :source, String
36
+ element :truncated, Boolean
37
+ element :in_reply_to_status_id, Integer
38
+ element :in_reply_to_user_id, Integer
39
+ element :favorited, Boolean
40
+ has_one :user, User
41
+ end
42
+
43
+ module PITA
44
+ class Item
45
+ include HappyMapper
46
+
47
+ tag 'Item' # if you put class in module you need tag
48
+ element :asin, String, :tag => 'ASIN'
49
+ element :detail_page_url, String, :tag => 'DetailPageURL'
50
+ element :manufacturer, String, :tag => 'Manufacturer', :deep => true
51
+ end
52
+
53
+ class Items
54
+ include HappyMapper
55
+
56
+ tag 'Items' # if you put class in module you need tag
57
+ element :total_results, Integer, :tag => 'TotalResults'
58
+ element :total_pages, Integer, :tag => 'TotalPages'
59
+ has_many :items, Item
60
+ end
61
+ end
62
+
63
+ describe HappyMapper do
64
+
65
+ describe "being included into another class" do
66
+ before do
67
+ Foo.instance_variable_set("@attributes", {})
68
+ Foo.instance_variable_set("@elements", {})
69
+ end
70
+ class Foo; include HappyMapper end
71
+
72
+ it "should set attributes to an array" do
73
+ Foo.attributes.should == []
74
+ end
75
+
76
+ it "should set @elements to a hash" do
77
+ Foo.elements.should == []
78
+ end
79
+
80
+ it "should allow adding an attribute" do
81
+ lambda {
82
+ Foo.attribute :name, String
83
+ }.should change(Foo, :attributes)
84
+ end
85
+
86
+ it "should be able to get all attributes in array" do
87
+ Foo.attribute :name, String
88
+ Foo.attributes.size.should == 1
89
+ end
90
+
91
+ it "should allow adding an element" do
92
+ lambda {
93
+ Foo.element :name, String
94
+ }.should change(Foo, :elements)
95
+ end
96
+
97
+ it "should be able to get all elements in array" do
98
+ Foo.element(:name, String)
99
+ Foo.elements.size.should == 1
100
+ end
101
+
102
+ it "should allow has one association" do
103
+ Foo.has_one(:user, User)
104
+ element = Foo.elements.first
105
+ element.name.should == 'user'
106
+ element.type.should == User
107
+ element.options[:single] = true
108
+ end
109
+
110
+ it "should allow has many association" do
111
+ Foo.has_many(:users, User)
112
+ element = Foo.elements.first
113
+ element.name.should == 'users'
114
+ element.type.should == User
115
+ element.options[:single] = false
116
+ end
117
+
118
+ it "should default tag name to class" do
119
+ Foo.get_tag_name.should == 'foo'
120
+ end
121
+
122
+ it "should allow setting tag name" do
123
+ Foo.tag('FooBar')
124
+ Foo.get_tag_name.should == 'FooBar'
125
+ end
126
+
127
+ it "should provide #parse" do
128
+ Foo.should respond_to(:parse)
129
+ end
130
+ end
131
+
132
+ describe "#attributes" do
133
+ it "should only return attributes for the current class" do
134
+ Post.attributes.size.should == 7
135
+ Status.attributes.size.should == 0
136
+ end
137
+ end
138
+
139
+ describe "#elements" do
140
+ it "should only return elements for the current class" do
141
+ Post.elements.size.should == 0
142
+ Status.elements.size.should == 9
143
+ end
144
+ end
145
+
146
+ describe "#parse (with xml attributes mapping to ruby attributes)" do
147
+ before do
148
+ @posts = Post.parse(File.read(File.dirname(__FILE__) + '/fixtures/posts.xml'))
149
+ end
150
+
151
+ it "should get the correct number of elements" do
152
+ @posts.size.should == 20
153
+ end
154
+
155
+ it "should properly create objects" do
156
+ first = @posts.first
157
+ first.href.should == 'http://roxml.rubyforge.org/'
158
+ first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
159
+ first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
160
+ first.tag.should == 'ruby xml gems mapping'
161
+ first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
162
+ first.others.should == 56
163
+ 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.'
164
+ end
165
+ end
166
+
167
+ describe "#parse (with xml elements mapping to ruby attributes)" do
168
+ before do
169
+ @statuses = Status.parse(File.read(File.dirname(__FILE__) + '/fixtures/statuses.xml'))
170
+ end
171
+
172
+ it "should get the correct number of elements" do
173
+ @statuses.size.should == 20
174
+ end
175
+
176
+ it "should properly create objects" do
177
+ first = @statuses.first
178
+ first.id.should == 882281424
179
+ first.created_at.should == Time.mktime(2008, 8, 9, 1, 38, 12)
180
+ first.source.should == 'web'
181
+ first.truncated.should be_false
182
+ first.in_reply_to_status_id.should == 1234
183
+ first.in_reply_to_user_id.should == 12345
184
+ first.favorited.should be_false
185
+ first.user.id.should == 4243
186
+ first.user.name.should == 'John Nunemaker'
187
+ first.user.screen_name.should == 'jnunemaker'
188
+ first.user.location.should == 'Mishawaka, IN, US'
189
+ first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball'
190
+ first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg'
191
+ first.user.url.should == 'http://addictedtonew.com'
192
+ first.user.protected.should be_false
193
+ first.user.followers_count.should == 486
194
+ end
195
+ end
196
+
197
+ # TODO: someone please get xml with namespaces working, kthxbai
198
+ describe "#parse (with xml that has namespace)" do
199
+ before do
200
+ file_contents = File.read(File.dirname(__FILE__) + '/fixtures/pita.xml')
201
+ @items = PITA::Items.parse(file_contents, :single => true, :use_default_namespace => true)
202
+ end
203
+
204
+ it "should properly create objects" do
205
+ @items.total_results.should == 22
206
+ @items.total_pages.should == 3
207
+ first = @items.items.first
208
+ first.asin.should == '0321480791'
209
+ first.detail_page_url.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh'
210
+ first.manufacturer.should == 'Addison-Wesley Professional'
211
+ end
212
+ end
213
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'happymapper')
@@ -0,0 +1,43 @@
1
+ desc 'Preps the gem for a new release'
2
+ task :prep_for_release do
3
+ require 'rio'
4
+ Rake::Task['manifest:refresh'].invoke
5
+ gemspec = %x[rake debug_gem]
6
+ lines = gemspec.split("\n")
7
+ rio('happymapper.gemspec') < lines[1, lines.length-1].join("\n")
8
+ end
9
+
10
+ desc 'Release the website and new gem version'
11
+ task :deploy => [:check_version, :website, :release] do
12
+ puts "Remember to create SVN tag:"
13
+ puts "svn copy svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/trunk " +
14
+ "svn+ssh://#{rubyforge_username}@rubyforge.org/var/svn/#{PATH}/tags/REL-#{VERS} "
15
+ puts "Suggested comment:"
16
+ puts "Tagging release #{CHANGES}"
17
+ end
18
+
19
+ desc 'Runs tasks website_generate and install_gem as a local deployment of the gem'
20
+ task :local_deploy => [:website_generate, :install_gem]
21
+
22
+ task :check_version do
23
+ unless ENV['VERSION']
24
+ puts 'Must pass a VERSION=x.y.z release version'
25
+ exit
26
+ end
27
+ unless ENV['VERSION'] == VERS
28
+ puts "Please update your version.rb to match the release version, currently #{VERS}"
29
+ exit
30
+ end
31
+ end
32
+
33
+ desc 'Install the package as a gem, without generating documentation(ri/rdoc)'
34
+ task :install_gem_no_doc => [:clean, :package] do
35
+ sh "#{'sudo ' unless Hoe::WINDOZE }gem install pkg/*.gem --no-rdoc --no-ri"
36
+ end
37
+
38
+ namespace :manifest do
39
+ desc 'Recreate Manifest.txt to include ALL files'
40
+ task :refresh do
41
+ `rake check_manifest | patch -p0 > Manifest.txt`
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ task :ruby_env do
2
+ RUBY_APP = if RUBY_PLATFORM =~ /java/
3
+ "jruby"
4
+ else
5
+ "ruby"
6
+ end unless defined? RUBY_APP
7
+ end
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
@@ -0,0 +1,17 @@
1
+ desc 'Generate website files'
2
+ task :website_generate => :ruby_env do
3
+ (Dir['website/**/*.txt'] - Dir['website/version*.txt']).each do |txt|
4
+ sh %{ #{RUBY_APP} script/txt2html #{txt} > #{txt.gsub(/txt$/,'html')} }
5
+ end
6
+ end
7
+
8
+ desc 'Upload website files to rubyforge'
9
+ task :website_upload do
10
+ host = "#{rubyforge_username}@rubyforge.org"
11
+ remote_dir = "/var/www/gforge-projects/#{PATH}/"
12
+ local_dir = 'website'
13
+ sh %{rsync -aCv #{local_dir}/ #{host}:#{remote_dir}}
14
+ end
15
+
16
+ desc 'Generate and upload website files'
17
+ task :website => [:website_upload, :publish_docs]
@@ -0,0 +1,47 @@
1
+ @media screen, projection {
2
+ /*
3
+ Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4
+ Code licensed under the BSD License:
5
+ http://developer.yahoo.net/yui/license.txt
6
+ version: 2.2.0
7
+ */
8
+ body {font:13px arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}select, input, textarea {font:99% arial,helvetica,clean,sans-serif;}pre, code {font:115% monospace;*font-size:100%;}body * {line-height:1.22em;}
9
+ body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}/*ol,ul {list-style:none;}*/caption,th {text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;}
10
+ /* end of yahoo reset and fonts */
11
+
12
+ body {color:#333; background:#4b1a1a; line-height:1.3;}
13
+ p {margin:0 0 20px;}
14
+ a {color:#4b1a1a;}
15
+ a:hover {text-decoration:none;}
16
+ strong {font-weight:bold;}
17
+ em {font-style:italics;}
18
+ h1,h2,h3,h4,h5,h6 {font-weight:bold;}
19
+ h1 {font-size:197%; margin:30px 0; color:#4b1a1a;}
20
+ h2 {font-size:174%; margin:20px 0; color:#b8111a;}
21
+ h3 {font-size:152%; margin:10px 0;}
22
+ h4 {font-size:129%; margin:10px 0;}
23
+ pre {background:#eee; margin:0 0 20px; padding:20px; border:1px solid #ccc; font-size:100%; overflow:auto;}
24
+ code {font-size:100%; margin:0; padding:0;}
25
+ ul, ol {margin:10px 0 10px 25px;}
26
+ ol li {margin:0 0 10px;}
27
+
28
+
29
+
30
+
31
+
32
+ div#wrapper {background:#fff; width:560px; margin:0 auto; padding:20px; border:10px solid #bc8c46; border-width:0 10px;}
33
+ div#header {position:relative; border-bottom:1px dotted; margin:0 0 10px; padding:0 0 10px;}
34
+ div#header p {margin:0; padding:0;}
35
+ div#header h1 {margin:0; padding:0;}
36
+ ul#nav {position:absolute; top:0; right:0; list-style:none; margin:0; padding:0;}
37
+ ul#nav li {display:inline; padding:0 0 0 5px;}
38
+ ul#nav li a {}
39
+ div#content {}
40
+ div#footer {margin:40px 0 0; border-top:1px dotted; padding:10px 0 0;}
41
+
42
+
43
+
44
+
45
+
46
+
47
+ }