happymapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }