mls 0.2.2 → 0.2.3

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.
Files changed (57) hide show
  1. data/.gitignore +1 -0
  2. data/README.rdoc +54 -0
  3. data/Rakefile +20 -2
  4. data/lib/mls.rb +307 -78
  5. data/lib/mls/errors.rb +13 -4
  6. data/lib/mls/model.rb +36 -5
  7. data/lib/mls/models/account.rb +74 -66
  8. data/lib/mls/models/address.rb +87 -6
  9. data/lib/mls/models/area.rb +27 -0
  10. data/lib/mls/models/flyer.rb +41 -0
  11. data/lib/mls/models/listing.rb +180 -34
  12. data/lib/mls/models/photo.rb +25 -3
  13. data/lib/mls/models/tour_request.rb +18 -31
  14. data/lib/mls/parser.rb +5 -4
  15. data/lib/mls/properties/datetime.rb +5 -1
  16. data/lib/mls/properties/decimal.rb +3 -1
  17. data/lib/mls/properties/hash.rb +7 -0
  18. data/lib/mls/resource.rb +35 -5
  19. data/lib/rdoc/generator/template/42floors/_context.rhtml +209 -0
  20. data/lib/rdoc/generator/template/42floors/_head.rhtml +7 -0
  21. data/lib/rdoc/generator/template/42floors/class.rhtml +39 -0
  22. data/lib/rdoc/generator/template/42floors/file.rhtml +35 -0
  23. data/lib/rdoc/generator/template/42floors/index.rhtml +13 -0
  24. data/lib/rdoc/generator/template/42floors/resources/apple-touch-icon.png +0 -0
  25. data/lib/rdoc/generator/template/42floors/resources/css/github.css +129 -0
  26. data/lib/rdoc/generator/template/42floors/resources/css/main.css +339 -0
  27. data/lib/rdoc/generator/template/42floors/resources/css/panel.css +389 -0
  28. data/lib/rdoc/generator/template/42floors/resources/css/reset.css +48 -0
  29. data/lib/rdoc/generator/template/42floors/resources/favicon.ico +0 -0
  30. data/lib/rdoc/generator/template/42floors/resources/i/arrows.png +0 -0
  31. data/lib/rdoc/generator/template/42floors/resources/i/results_bg.png +0 -0
  32. data/lib/rdoc/generator/template/42floors/resources/i/tree_bg.png +0 -0
  33. data/lib/rdoc/generator/template/42floors/resources/js/highlight.pack.js +1 -0
  34. data/lib/rdoc/generator/template/42floors/resources/js/jquery-1.3.2.min.js +19 -0
  35. data/lib/rdoc/generator/template/42floors/resources/js/jquery-effect.js +593 -0
  36. data/lib/rdoc/generator/template/42floors/resources/js/main.js +20 -0
  37. data/lib/rdoc/generator/template/42floors/resources/js/searchdoc.js +442 -0
  38. data/lib/rdoc/generator/template/42floors/resources/panel/index.html +73 -0
  39. data/lib/rdoc/generator/template/42floors/se_index.rhtml +8 -0
  40. data/mls.gemspec +7 -4
  41. data/test/factories/account.rb +18 -0
  42. data/test/factories/address.rb +15 -0
  43. data/test/factories/listing.rb +30 -0
  44. data/test/factories/tour_request.rb +9 -0
  45. data/test/fixtures/flyer.pdf +68 -0
  46. data/test/test_helper.rb +44 -5
  47. data/test/units/models/test_account.rb +20 -43
  48. data/test/units/models/test_flyer.rb +22 -0
  49. data/test/units/models/test_listing.rb +119 -0
  50. data/test/units/models/test_photo.rb +136 -3
  51. data/test/units/models/test_tour_request.rb +25 -20
  52. data/test/units/test_errors.rb +12 -4
  53. data/test/units/test_mls.rb +263 -3
  54. data/test/units/test_resource.rb +1 -0
  55. metadata +78 -57
  56. data/lib/mls/models/user.rb +0 -7
  57. data/lib/mls/version.rb +0 -3
@@ -1,7 +1,9 @@
1
1
  class MLS::Property::Decimal < MLS::Property
2
2
 
3
3
  def load(value) # from_json
4
- if value.is_a?(BigDecimal)
4
+ if value.nil?
5
+ nil
6
+ elsif value.is_a?(BigDecimal)
5
7
  value
6
8
  else
7
9
  BigDecimal.new(value.to_s)
@@ -0,0 +1,7 @@
1
+ class MLS::Property::Hash < MLS::Property
2
+
3
+ def load(value) # from_json
4
+ value
5
+ end
6
+
7
+ end
data/lib/mls/resource.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  class MLS::Resource
2
2
 
3
- attr_reader :errors, :persisted
3
+ attr_reader :persisted
4
+ attr_accessor :errors
4
5
 
5
6
  def self.inherited(subclass)
6
7
  subclass.extend(MLS::Model)
@@ -23,14 +24,42 @@ class MLS::Resource
23
24
  end
24
25
 
25
26
  def save
27
+ new_record? ? create : update
28
+ end
29
+
30
+ def save!
26
31
  new_record? ? create! : update!
27
32
  end
28
-
33
+
34
+ def update!
35
+ update || raise(MLS::Exception::RecordInvalid)
36
+ end
37
+
38
+ def create!
39
+ create || raise(MLS::Exception::RecordInvalid)
40
+ end
41
+
42
+ def ==(other)
43
+ self.class == other.class && properties_for_comparison == other.properties_for_comparison
44
+ end
45
+
29
46
  # Properties ===================================================================================================
30
47
 
31
48
  def properties
32
49
  self.class.properties
33
50
  end
51
+
52
+ def properties_for_comparison
53
+ compare = {}
54
+ properties.reject{ |k, p| properties_excluded_from_comparison.include?(k) }.each do |k, p|
55
+ compare[k] = self.send(properties[k].name.to_sym)
56
+ end
57
+ compare
58
+ end
59
+
60
+ def properties_excluded_from_comparison
61
+ self.class.properties_excluded_from_comparison
62
+ end
34
63
 
35
64
  def set_default_values
36
65
  properties.each do |name, property|
@@ -39,7 +68,7 @@ class MLS::Resource
39
68
  end
40
69
 
41
70
  def update_attributes(attrs)
42
- attrs.each { |k, v| self.send("#{k}=".to_sym, v) }
71
+ attrs.each { |k, v| self.send("#{k}=".to_sym, v) } unless attrs.nil?
43
72
  end
44
73
 
45
74
  # Combo Breaker ================================================================================================
@@ -48,7 +77,8 @@ class MLS::Resource
48
77
  hash = {}
49
78
 
50
79
  properties.each do |name, property|
51
- serialize = property.options[:serialize] || :always
80
+ serialize = property.options[:serialize]
81
+ serialize = :always if serialize.nil?
52
82
  case serialize
53
83
  when :always
54
84
  hash[name] = property.dump(self.send(name))
@@ -66,4 +96,4 @@ class MLS::Resource
66
96
  persisted? ? [id] : nil
67
97
  end
68
98
 
69
- end
99
+ end
@@ -0,0 +1,209 @@
1
+ <div id="content">
2
+ <% unless (description = context.description).empty? %>
3
+ <div class="description">
4
+ <%= description %>
5
+ </div>
6
+ <% end %>
7
+
8
+
9
+ <% unless context.requires.empty? %>
10
+ <!-- File only: requires -->
11
+ <div class="sectiontitle">Required Files</div>
12
+ <ul>
13
+ <% context.requires.each do |req| %>
14
+ <li><%= h req.name %></li>
15
+ <% end %>
16
+ </ul>
17
+ <% end %>
18
+
19
+
20
+ <% sections = context.sections.select { |s| s.title }.sort_by{ |s| s.title.to_s } %>
21
+ <% unless sections.empty? then %>
22
+ <!-- Sections -->
23
+ <div class="sectiontitle">Sections</div>
24
+ <ul>
25
+ <% sections.each do |section| %>
26
+ <li><a href="#<%= section.aref %>"><%= h section.title %></a></li>
27
+ <% end %>
28
+ </ul>
29
+ <% end %>
30
+
31
+
32
+ <% unless context.classes_and_modules.empty? %>
33
+ <!-- Namespace -->
34
+ <div class="sectiontitle">Namespace</div>
35
+ <ul>
36
+ <% (context.modules.sort + context.classes.sort).each do |mod| %>
37
+ <li>
38
+ <span class="type"><%= mod.type.upcase %></span>
39
+ <a href="<%= context.aref_to mod.path %>"><%= mod.full_name %></a>
40
+ </li>
41
+ <% end %>
42
+ </ul>
43
+ <% end %>
44
+
45
+
46
+ <% unless context.method_list.empty? %>
47
+ <!-- Method ref -->
48
+ <div class="sectiontitle">Methods</div>
49
+ <dl class="methods">
50
+ <% each_letter_group(context.method_list) do |group| %>
51
+ <dt><%= group[:name] %></dt>
52
+ <dd>
53
+ <ul>
54
+ <% group[:methods].each_with_index do |method, i| %>
55
+ <%
56
+ comma = group[:methods].size == i+1 ? '' : ','
57
+ %>
58
+ <li>
59
+ <a href="#<%= method.aref %>"><%= h method.name %></a><%= comma %>
60
+ </li>
61
+ <% end %>
62
+ </ul>
63
+ </dd>
64
+ <% end %>
65
+ </dl>
66
+ <% end %>
67
+
68
+ <% unless context.includes.empty? %>
69
+ <!-- Includes -->
70
+ <div class="sectiontitle">Included Modules</div>
71
+ <ul>
72
+ <% context.includes.each do |inc| %>
73
+ <li>
74
+ <% unless String === inc.module %>
75
+ <a href="<%= context.aref_to inc.module.path %>">
76
+ <%= h inc.module.full_name %>
77
+ </a>
78
+ <% else %>
79
+ <%= h inc.name %>
80
+ <% end %>
81
+ </li>
82
+ <% end %>
83
+ </ul>
84
+ <% end %>
85
+
86
+
87
+
88
+ <% context.each_section do |section, constants, attributes| %>
89
+
90
+ <% if section.title then %>
91
+ <div class="contenttitle" id="<%= h section.aref %>">
92
+ <%= h section.title %>
93
+ </div>
94
+ <% end %>
95
+
96
+ <% if section.comment then %>
97
+ <div class="description">
98
+ <%= section.description %>
99
+ </div>
100
+ <% end %>
101
+
102
+ <% unless constants.empty? %>
103
+ <!-- Section constants -->
104
+ <div class="sectiontitle">Constants</div>
105
+ <table border='0' cellpadding='5'>
106
+ <% context.each_constant do |const| %>
107
+ <tr valign='top'>
108
+ <td class="attr-name"><%= h const.name %></td>
109
+ <td>=</td>
110
+ <td class="attr-value"><%= h const.value %></td>
111
+ </tr>
112
+ <% if const.comment %>
113
+ <tr valign='top'>
114
+ <td>&nbsp;</td>
115
+ <td colspan="2" class="attr-desc"><%= const.description.strip %></td>
116
+ </tr>
117
+ <% end %>
118
+ <% end %>
119
+ </table>
120
+ <% end %>
121
+
122
+
123
+ <% unless attributes.empty? %>
124
+ <!-- Section attributes -->
125
+ <div class="sectiontitle">Attributes</div>
126
+ <table border='0' cellpadding='5'>
127
+ <% attributes.each do |attrib| %>
128
+ <tr valign='top'>
129
+ <td class='attr-rw'>
130
+ [<%= attrib.rw %>]
131
+ </td>
132
+ <td class='attr-name'><%= h attrib.name %></td>
133
+ <td class='attr-desc'><%= attrib.description.strip %></td>
134
+ </tr>
135
+ <% end %>
136
+ </table>
137
+ <% end %>
138
+
139
+
140
+ <!-- Methods -->
141
+ <%
142
+ context.methods_by_type(section).each do |type, visibilities|
143
+ next if visibilities.empty?
144
+
145
+ visibilities.each do |visibility, methods|
146
+ next if methods.empty?
147
+ %>
148
+ <div class="sectiontitle"><%= type.capitalize %> <%= visibility.to_s.capitalize %> methods</div>
149
+ <% methods.each do |method| %>
150
+ <div class="method">
151
+ <div class="title method-title" id="<%= method.aref %>">
152
+ <% if method.call_seq %>
153
+ <a name="<%= method.aref %>"></a><b><%= method.call_seq.gsub(/->/, '&rarr;') %></b>
154
+ <% else %>
155
+ <a name="<%= method.aref %>"></a><b><%= h method.name %></b><%= h method.params %>
156
+ <% end %>
157
+ </div>
158
+
159
+ <% if method.comment %>
160
+ <div class="description">
161
+ <%= method.description.strip %>
162
+ </div>
163
+ <% end %>
164
+
165
+ <% unless method.aliases.empty? %>
166
+ <div class="aka">
167
+ Also aliased as: <%= method.aliases.map do |aka|
168
+ if aka.parent then # HACK lib/rexml/encodings
169
+ %{<a href="#{context.aref_to aka.path}">#{h aka.name}</a>}
170
+ else
171
+ h aka.name
172
+ end
173
+ end.join ", " %>
174
+ </div>
175
+ <% end %>
176
+
177
+ <% if method.token_stream %>
178
+ <% markup = method.sdoc_markup_code %>
179
+ <div class="sourcecode">
180
+ <%
181
+ # generate github link
182
+ github = if options.github
183
+ if markup =~ /File\s(\S+), line (\d+)/
184
+ path = $1
185
+ line = $2.to_i
186
+ end
187
+ path && github_url(path)
188
+ else
189
+ false
190
+ end
191
+ %>
192
+ <p class="source-link">
193
+ Source:
194
+ <a href="javascript:toggleSource('<%= method.aref %>_source')" id="l_<%= method.aref %>_source">show</a>
195
+ <% if github %>
196
+ | <a href="<%= "#{github}#L#{line}" %>" target="_blank" class="github_url">on GitHub</a>
197
+ <% end %>
198
+ </p>
199
+ <div id="<%= method.aref %>_source" class="dyn-source">
200
+ <pre><%= markup %></pre>
201
+ </div>
202
+ </div>
203
+ <% end %>
204
+ </div>
205
+ <% end #methods.each %>
206
+ <% end #visibilities.each %>
207
+ <% end #context.methods_by_type %>
208
+ <% end #context.each_section %>
209
+ </div>
@@ -0,0 +1,7 @@
1
+ <link rel="stylesheet" href="<%= "#{rel_prefix}/css/reset.css" %>" type="text/css" media="screen" />
2
+ <link rel="stylesheet" href="<%= "#{rel_prefix}/css/main.css" %>" type="text/css" media="screen" />
3
+ <link rel="stylesheet" href="<%= "#{rel_prefix}/css/github.css" %>" type="text/css" media="screen" />
4
+ <script src="<%= "#{rel_prefix}/js/jquery-1.3.2.min.js" %>" type="text/javascript" charset="utf-8"></script>
5
+ <script src="<%= "#{rel_prefix}/js/jquery-effect.js" %>" type="text/javascript" charset="utf-8"></script>
6
+ <script src="<%= "#{rel_prefix}/js/main.js" %>" type="text/javascript" charset="utf-8"></script>
7
+ <script src="<%= "#{rel_prefix}/js/highlight.pack.js" %>" type="text/javascript" charset="utf-8"></script>
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <title><%= h klass.full_name %></title>
7
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= @options.charset %>" />
8
+ <%= include_template '_head.rhtml', {:rel_prefix => rel_prefix} %>
9
+ </head>
10
+
11
+ <body>
12
+ <div class="banner">
13
+ <% if ENV['HORO_PROJECT_NAME'] %>
14
+ <span><%= ERB::Util.html_escape(ENV['HORO_PROJECT_NAME']) %> <%= ERB::Util.html_escape(ENV['HORO_PROJECT_VERSION']) %></span><br />
15
+ <% end %>
16
+ <h1>
17
+ <span class="type"><%= klass.module? ? 'Module' : 'Class' %></span>
18
+ <%= h klass.full_name %>
19
+ <% if klass.type == 'class' %>
20
+ <span class="parent">&lt;
21
+ <% if String === klass.superclass %>
22
+ <%= klass.superclass %>
23
+ <% elsif !klass.superclass.nil? %>
24
+ <a href="<%= klass.aref_to klass.superclass.path %>"><%= h klass.superclass.full_name %></a>
25
+ <% end %>
26
+ </span>
27
+ <% end %>
28
+ </h1>
29
+ <ul class="files">
30
+ <% klass.in_files.each do |file| %>
31
+ <li><a href="<%= "#{rel_prefix}/#{h file.path}" %>"><%= h file.absolute_name %></a></li>
32
+ <% end %>
33
+ </ul>
34
+ </div>
35
+ <div id="bodyContent">
36
+ <%= include_template '_context.rhtml', {:context => klass, :rel_prefix => rel_prefix} %>
37
+ </div>
38
+ </body>
39
+ </html>
@@ -0,0 +1,35 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <title><%= h file.name %></title>
7
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= @options.charset %>" />
8
+ <%= include_template '_head.rhtml', {:rel_prefix => rel_prefix} %>
9
+ </head>
10
+
11
+ <body>
12
+ <div class="banner">
13
+ <% if ENV['HORO_PROJECT_NAME'] %>
14
+ <span><%= ERB::Util.html_escape(ENV['HORO_PROJECT_NAME']) %> <%= ERB::Util.html_escape(ENV['HORO_PROJECT_VERSION']) %></span><br />
15
+ <% end %>
16
+ <h1>
17
+ <%= h file.name %>
18
+ </h1>
19
+ <ul class="files">
20
+ <% github = github_url(file.relative_name) if options.github %>
21
+ <li>
22
+ <%= h file.relative_name %>
23
+ <% if github %>
24
+ <a href="<%= github %>" target="_blank" class="github_url">on GitHub</a>
25
+ <% end %>
26
+ </li>
27
+ <li>Last modified: <%= file.file_stat.mtime %></li>
28
+ </ul>
29
+ </div>
30
+
31
+ <div id="bodyContent">
32
+ <%= include_template '_context.rhtml', {:context => file, :rel_prefix => rel_prefix} %>
33
+ </div>
34
+ </body>
35
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html
2
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= @options.charset %>" />
7
+ <title><%= @options.title %></title>
8
+ </head>
9
+ <frameset cols="300,*" frameborder="1" border="1" bordercolor="#999999" framespacing="1">
10
+ <frame src="panel/index.html" title="Search" name="panel" />
11
+ <frame src="<%= index_path %>" name="docwin" />
12
+ </frameset>
13
+ </html>
@@ -0,0 +1,129 @@
1
+ /*
2
+
3
+ github.com style (c) Vasily Polovnyov <vast@whiteants.net>
4
+
5
+ */
6
+
7
+ pre code {
8
+ display: block; padding: 0.5em;
9
+ color: #000;
10
+ background: #f8f8ff
11
+ }
12
+
13
+ pre .comment,
14
+ pre .template_comment,
15
+ pre .diff .header,
16
+ pre .javadoc {
17
+ color: #998;
18
+ font-style: italic
19
+ }
20
+
21
+ pre .keyword,
22
+ pre .css .rule .keyword,
23
+ pre .winutils,
24
+ pre .javascript .title,
25
+ pre .lisp .title,
26
+ pre .subst {
27
+ color: #000;
28
+ font-weight: bold
29
+ }
30
+
31
+ pre .number,
32
+ pre .hexcolor {
33
+ color: #40a070
34
+ }
35
+
36
+ pre .string,
37
+ pre .tag .value,
38
+ pre .phpdoc,
39
+ pre .tex .formula {
40
+ color: #d14
41
+ }
42
+
43
+ pre .title,
44
+ pre .id {
45
+ color: #900;
46
+ font-weight: bold
47
+ }
48
+
49
+ pre .javascript .title,
50
+ pre .lisp .title,
51
+ pre .subst {
52
+ font-weight: normal
53
+ }
54
+
55
+ pre .class .title,
56
+ pre .haskell .label,
57
+ pre .tex .command {
58
+ color: #458;
59
+ font-weight: bold
60
+ }
61
+
62
+ pre .tag,
63
+ pre .tag .title,
64
+ pre .rules .property,
65
+ pre .django .tag .keyword {
66
+ color: #000080;
67
+ font-weight: normal
68
+ }
69
+
70
+ pre .attribute,
71
+ pre .variable,
72
+ pre .instancevar,
73
+ pre .lisp .body {
74
+ color: #008080
75
+ }
76
+
77
+ pre .regexp {
78
+ color: #009926
79
+ }
80
+
81
+ pre .class {
82
+ color: #458;
83
+ font-weight: bold
84
+ }
85
+
86
+ pre .symbol,
87
+ pre .ruby .symbol .string,
88
+ pre .ruby .symbol .keyword,
89
+ pre .ruby .symbol .keymethods,
90
+ pre .lisp .keyword,
91
+ pre .tex .special,
92
+ pre .input_number {
93
+ color: #990073
94
+ }
95
+
96
+ pre .builtin,
97
+ pre .built_in,
98
+ pre .lisp .title {
99
+ color: #0086b3
100
+ }
101
+
102
+ pre .preprocessor,
103
+ pre .pi,
104
+ pre .doctype,
105
+ pre .shebang,
106
+ pre .cdata {
107
+ color: #999;
108
+ font-weight: bold
109
+ }
110
+
111
+ pre .deletion {
112
+ background: #fdd
113
+ }
114
+
115
+ pre .addition {
116
+ background: #dfd
117
+ }
118
+
119
+ pre .diff .change {
120
+ background: #0086b3
121
+ }
122
+
123
+ pre .chunk {
124
+ color: #aaa
125
+ }
126
+
127
+ pre .tex .formula {
128
+ opacity: 0.5;
129
+ }