mls 0.14.0 → 1.0.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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/Rakefile +6 -6
  4. data/lib/mls.rb +73 -427
  5. data/lib/mls/account.rb +15 -0
  6. data/lib/mls/address.rb +4 -0
  7. data/lib/mls/agency.rb +6 -0
  8. data/lib/mls/brokerage.rb +7 -0
  9. data/lib/mls/coworking_space.rb +5 -0
  10. data/lib/mls/floorplan.rb +11 -0
  11. data/lib/mls/flyer.rb +11 -0
  12. data/lib/mls/lease.rb +2 -0
  13. data/lib/mls/listing.rb +135 -0
  14. data/lib/mls/locality.rb +6 -0
  15. data/lib/mls/photo.rb +18 -0
  16. data/lib/mls/property.rb +24 -0
  17. data/lib/mls/region.rb +13 -0
  18. data/lib/mls/sale.rb +2 -0
  19. data/lib/mls/space.rb +3 -0
  20. data/lib/mls/sublease.rb +2 -0
  21. data/lib/mls/use.rb +25 -0
  22. data/mls.gemspec +11 -15
  23. data/test/mls/attribute_test.rb +55 -0
  24. data/test/mls/resource_test.rb +31 -0
  25. data/test/mls_test.rb +27 -0
  26. data/test/test_helper.rb +26 -27
  27. metadata +43 -75
  28. data/lib/mls/attribute.rb +0 -44
  29. data/lib/mls/attributes/array.rb +0 -11
  30. data/lib/mls/attributes/boolean.rb +0 -9
  31. data/lib/mls/attributes/datetime.rb +0 -25
  32. data/lib/mls/attributes/decimal.rb +0 -21
  33. data/lib/mls/attributes/fixnum.rb +0 -16
  34. data/lib/mls/attributes/hash.rb +0 -15
  35. data/lib/mls/attributes/string.rb +0 -15
  36. data/lib/mls/errors.rb +0 -29
  37. data/lib/mls/factories/account.rb +0 -34
  38. data/lib/mls/factories/address.rb +0 -16
  39. data/lib/mls/factories/listing.rb +0 -29
  40. data/lib/mls/factories_helper.rb +0 -7
  41. data/lib/mls/model.rb +0 -125
  42. data/lib/mls/models/account.rb +0 -174
  43. data/lib/mls/models/address.rb +0 -58
  44. data/lib/mls/models/brokerage.rb +0 -31
  45. data/lib/mls/models/floorplan.rb +0 -45
  46. data/lib/mls/models/flyer.rb +0 -45
  47. data/lib/mls/models/listing.rb +0 -394
  48. data/lib/mls/models/pdf.rb +0 -15
  49. data/lib/mls/models/photo.rb +0 -40
  50. data/lib/mls/models/property.rb +0 -114
  51. data/lib/mls/models/region.rb +0 -56
  52. data/lib/mls/models/tour.rb +0 -54
  53. data/lib/mls/models/video.rb +0 -18
  54. data/lib/mls/parser.rb +0 -74
  55. data/lib/mls/resource.rb +0 -99
  56. data/lib/rdoc/generator/template/42floors/_context.rhtml +0 -209
  57. data/lib/rdoc/generator/template/42floors/_head.rhtml +0 -7
  58. data/lib/rdoc/generator/template/42floors/class.rhtml +0 -39
  59. data/lib/rdoc/generator/template/42floors/file.rhtml +0 -35
  60. data/lib/rdoc/generator/template/42floors/index.rhtml +0 -13
  61. data/lib/rdoc/generator/template/42floors/resources/apple-touch-icon.png +0 -0
  62. data/lib/rdoc/generator/template/42floors/resources/css/github.css +0 -129
  63. data/lib/rdoc/generator/template/42floors/resources/css/main.css +0 -339
  64. data/lib/rdoc/generator/template/42floors/resources/css/panel.css +0 -389
  65. data/lib/rdoc/generator/template/42floors/resources/css/reset.css +0 -48
  66. data/lib/rdoc/generator/template/42floors/resources/favicon.ico +0 -0
  67. data/lib/rdoc/generator/template/42floors/resources/i/arrows.png +0 -0
  68. data/lib/rdoc/generator/template/42floors/resources/i/results_bg.png +0 -0
  69. data/lib/rdoc/generator/template/42floors/resources/i/tree_bg.png +0 -0
  70. data/lib/rdoc/generator/template/42floors/resources/js/highlight.pack.js +0 -1
  71. data/lib/rdoc/generator/template/42floors/resources/js/jquery-1.3.2.min.js +0 -19
  72. data/lib/rdoc/generator/template/42floors/resources/js/jquery-effect.js +0 -593
  73. data/lib/rdoc/generator/template/42floors/resources/js/main.js +0 -20
  74. data/lib/rdoc/generator/template/42floors/resources/js/searchdoc.js +0 -442
  75. data/lib/rdoc/generator/template/42floors/resources/panel/index.html +0 -73
  76. data/lib/rdoc/generator/template/42floors/se_index.rhtml +0 -8
  77. data/test/units/properties/test_boolean.rb +0 -4
  78. data/test/units/test_errors.rb +0 -32
  79. data/test/units/test_mls.rb +0 -294
  80. data/test/units/test_property.rb +0 -35
@@ -0,0 +1,15 @@
1
+ class Account < MLS::Model
2
+
3
+ include MLS::Avatar
4
+
5
+ belongs_to :brokerage
6
+
7
+ has_many :agencies, :inverse_of => :agent, :foreign_key => :agent_id
8
+
9
+ # def self.authenticate(email, pass)
10
+ # account = where(arel_table[:email].eq(email.try(:downcase)).and(arel_table[:password_digest].not_eq(nil))).first
11
+ # account && BCrypt::Password.new(account.password_digest) == pass ? account : nil
12
+ # end
13
+
14
+
15
+ end
@@ -0,0 +1,4 @@
1
+ class Address < MLS::Model
2
+
3
+
4
+ end
@@ -0,0 +1,6 @@
1
+ class Agency < MLS::Model
2
+
3
+ belongs_to :subject, polymorphic: true
4
+ belongs_to :agent, :class_name => 'Account', :inverse_of => :agencies
5
+
6
+ end
@@ -0,0 +1,7 @@
1
+ class Brokerage < MLS::Model
2
+
3
+ def name
4
+ common_name || proper_name
5
+ end
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ class CoworkingSpace < Listing
2
+
3
+ has_many :spaces
4
+
5
+ end
@@ -0,0 +1,11 @@
1
+ class Floorplan < MLS::Model
2
+
3
+ include MLS::Avatar
4
+
5
+ has_one :listing
6
+
7
+ def url
8
+ "http://#{MLS.asset_host}/floorplans/#{file_digest}/compressed/#{file_name}"
9
+ end
10
+
11
+ end
@@ -0,0 +1,11 @@
1
+ class Flyer < MLS::Model
2
+
3
+ include MLS::Avatar
4
+
5
+ has_one :listing
6
+
7
+ def url
8
+ "http://#{MLS.asset_host}/flyers/#{file_digest}/compressed/#{file_name}"
9
+ end
10
+
11
+ end
@@ -0,0 +1,2 @@
1
+ class Lease < Listing
2
+ end
@@ -0,0 +1,135 @@
1
+ class Listing < MLS::Model
2
+
3
+ include MLS::Slugger
4
+ include MLS::Avatar
5
+
6
+ WORKFLOW_STATES = %w(visible processing invisible expired)
7
+ LEASE_STATES = %w(listed leased)
8
+ TYPES = %w(lease sublease coworking_space)
9
+ SPACE_TYPES = %w(unit floor building)
10
+ LEASE_TERMS = ['Full Service', 'NNN', 'Modified Gross']
11
+ RATE_UNITS = ['/sqft/yr', '/sqft/mo', '/mo', '/yr', '/desk/mo']
12
+ USES = ["Office", "Creative", "Loft", "Medical Office", "Flex Space", "R&D", "Office Showroom", "Industrial", "Retail"]
13
+ SOURCE_TYPES = %w(website flyer)
14
+ CHANNELS = %w(excavator mls staircase broker_dashboard)
15
+
16
+ belongs_to :property
17
+ belongs_to :floorplan
18
+ belongs_to :flyer
19
+
20
+ has_many :photos, -> { order('photos.order ASC') }, :as => :subject, :inverse_of => :subject
21
+
22
+ has_many :agencies, -> { order(:order) }, :as => :subject
23
+ has_many :agents, :through => :agencies, :source => :agent
24
+
25
+ # has_one :address
26
+ # has_one :contact
27
+ #
28
+ # has_many :addresses
29
+
30
+ # has_many :comments
31
+ # has_many :regions
32
+ # has_many :agents
33
+
34
+ # has_many :favoritizations, :foreign_key => :favorite_id
35
+ # has_many :accounts, :through => :favoritizations
36
+ # has_many :inquiries, :as => :subject, :inverse_of => :subject
37
+ # has_many :agencies, -> { order('"order"') }, :dependent => :destroy, :inverse_of => :subject, :as => :subject
38
+ # has_many :agents, -> { order('agencies.order') }, :through => :agencies, :inverse_of => :listings, :source => :agent
39
+ # has_many :email_proxies, :as => :subject, :inverse_of => :subject
40
+ # has_many :lead_listings, :dependent => :delete_all
41
+ #
42
+ has_and_belongs_to_many :uses
43
+
44
+ def contact
45
+ @contact ||= agents.first
46
+ end
47
+ alias_method :default_contact, :contact
48
+
49
+ def rate(units=nil)
50
+ return nil if !read_attribute(:rate)
51
+ units ||= rate_units
52
+
53
+ price = if rate_units == '/sqft/mo'
54
+ if units == '/sqft/mo'
55
+ read_attribute(:rate)
56
+ elsif units == '/sqft/yr'
57
+ read_attribute(:rate) * 12.0
58
+ elsif units == '/mo'
59
+ read_attribute(:rate) * size
60
+ elsif units == '/yr'
61
+ read_attribute(:rate) * size * 12.0
62
+ else
63
+ raise "Invalid rate conversion (#{rate_units} => #{units})"
64
+ end
65
+
66
+ elsif rate_units == '/sqft/yr'
67
+ if units == '/sqft/mo'
68
+ read_attribute(:rate) / 12.0
69
+ elsif units == '/sqft/yr'
70
+ read_attribute(:rate)
71
+ elsif units == '/mo'
72
+ (read_attribute(:rate) * size) / 12.0
73
+ elsif units == '/yr'
74
+ read_attribute(:rate) * size
75
+ else
76
+ raise "Invalid rate conversion (#{rate_units} => #{units})"
77
+ end
78
+
79
+ elsif rate_units == '/mo'
80
+ if units == '/sqft/mo'
81
+ read_attribute(:rate) / size.to_f
82
+ elsif units == '/sqft/yr'
83
+ (read_attribute(:rate) * 12) / size.to_f
84
+ elsif units == '/mo'
85
+ read_attribute(:rate)
86
+ elsif units == '/yr'
87
+ read_attribute(:rate) * 12
88
+ else
89
+ raise "Invalid rate conversion (#{rate_units} => #{units})"
90
+ end
91
+
92
+ elsif rate_units == '/yr'
93
+ if units == '/sqft/mo'
94
+ (read_attribute(:rate) / 12.0) / size.to_f
95
+ elsif units == '/sqft/yr'
96
+ read_attribute(:rate) / size.to_f
97
+ elsif units == '/mo'
98
+ read_attribute(:rate) / 12.0
99
+ elsif units == '/yr'
100
+ read_attribute(:rate)
101
+ else
102
+ raise "Invalid rate conversion (#{rate_units} => #{units})"
103
+ end
104
+
105
+ end
106
+
107
+ price.round(2)
108
+ end
109
+
110
+ def name
111
+ return read_attribute(:name) if read_attribute(:name)
112
+
113
+ case space_type
114
+ when 'unit'
115
+ if unit
116
+ "Unit #{unit}"
117
+ elsif floor
118
+ "#{floor.ordinalize} Floor Unit"
119
+ else
120
+ "Unit Lease"
121
+ end
122
+ when 'building'
123
+ "Entire Building"
124
+ when 'floor'
125
+ if floor
126
+ "#{floor.ordinalize} Floor"
127
+ elsif unit
128
+ "Unit #{unit}"
129
+ else
130
+ "Floor Lease"
131
+ end
132
+ end
133
+ end
134
+
135
+ end
@@ -0,0 +1,6 @@
1
+ class Locality < MLS::Model
2
+
3
+ belongs_to :region
4
+ belongs_to :property
5
+
6
+ end
@@ -0,0 +1,18 @@
1
+ class Photo < MLS::Model
2
+
3
+ belongs_to :subject, :polymorphic => true, :inverse_of => :photos
4
+
5
+ def url(options={})
6
+ options.reverse_merge!({
7
+ :style => nil,
8
+ :protocol => "http",
9
+ :bg => nil,
10
+ :format => "jpg"
11
+ });
12
+ url_params = {s: options[:style], bg: options[:bg]}.select{ |k, v| v }
13
+ result = "#{options[:protocol]}://#{MLS.image_host}/#{digest}.#{options[:format]}"
14
+ result += "?#{url_params.to_param}" if url_params.size > 0
15
+
16
+ result
17
+ end
18
+ end
@@ -0,0 +1,24 @@
1
+ class Property < MLS::Model
2
+
3
+ include MLS::Slugger
4
+ include MLS::Avatar
5
+
6
+ belongs_to :contact, :class_name => 'Account'
7
+
8
+ has_many :listings
9
+ has_many :localities
10
+ has_many :regions, :through => :localities
11
+ has_many :photos, -> { order('photos.order ASC') }, :as => :subject, :inverse_of => :subject
12
+ # has_many :regions
13
+
14
+ has_many :addresses
15
+ has_one :address, -> { where(:primary => true) }
16
+
17
+ def default_contact
18
+ @default_contact ||= listings.where(lease_state: :listed, state: :visible)
19
+ .where({ type: ['Lease', 'Sublease', 'Sale']})
20
+ .order(size: :desc)
21
+ .first.try(:contact)
22
+ end
23
+
24
+ end
@@ -0,0 +1,13 @@
1
+ class Region < MLS::Model
2
+
3
+ include MLS::Slugger
4
+
5
+ self.inheritance_column = 'inheritance_type'
6
+
7
+ belongs_to :cover_photo, :class_name => 'Photo'
8
+
9
+ has_and_belongs_to_many :parents, :join_table => 'regions_regions', :class_name => 'Region', :foreign_key => 'child_id', :association_foreign_key => 'parent_id'
10
+ has_and_belongs_to_many :children, :join_table => 'regions_regions', :class_name => 'Region', :foreign_key => 'parent_id', :association_foreign_key => 'child_id'
11
+
12
+
13
+ end
@@ -0,0 +1,2 @@
1
+ class Sale < Listing
2
+ end
@@ -0,0 +1,3 @@
1
+ class Space < MLS::Model
2
+
3
+ end
@@ -0,0 +1,2 @@
1
+ class Sublease < Listing
2
+ end
@@ -0,0 +1,25 @@
1
+ class Use < MLS::Model
2
+
3
+ # has_ltree_hierarchy
4
+
5
+ has_many :children, class_name: 'Use', foreign_key: 'parent_id', inverse_of: :parent
6
+
7
+ has_and_belongs_to_many :listings
8
+ # has_and_belongs_to_many :properties
9
+
10
+ def descendants(uses = nil)
11
+ # Recursive self + children of children
12
+ uses ||= [self]
13
+ self.children.each do |child|
14
+ uses << child
15
+ uses = child.descendants(uses)
16
+ end
17
+ uses
18
+ end
19
+
20
+ # # Scope taken from https://github.com/RISCfuture/hierarchy/blob/master/lib/hierarchy.rb
21
+ # def self.self_and_descendents_of(use)
22
+ # where("path <@ ?", use.path)
23
+ # end
24
+
25
+ end
@@ -3,9 +3,9 @@ $:.push File.expand_path("../lib", __FILE__)
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "mls"
6
- s.version = '0.14.0'
7
- s.authors = ["James R. Bracy", "Jon Bracy"]
8
- s.email = ["james@42floors.com"]
6
+ s.version = '1.0.0'
7
+ s.authors = ["Jon Bracy", "James R. Bracy"]
8
+ s.email = ["jon@42floors.com", "james@42floors.com"]
9
9
  s.homepage = "http://mls.42floors.com"
10
10
  s.summary = %q{42Floors MLS Client}
11
11
  s.description = %q{Ruby library for integrating with the 42Floors MLS}
@@ -22,18 +22,14 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency 'rdoc'
23
23
  s.add_development_dependency 'sdoc'
24
24
  s.add_development_dependency 'bundler'
25
- s.add_development_dependency 'minitest', '4.7.4'
26
- s.add_development_dependency 'turn'
27
- # s.add_development_dependency 'faker'
28
- # s.add_development_dependency 'factory_girl'
29
- s.add_development_dependency 'fakeweb'
25
+ s.add_development_dependency 'minitest'
26
+ s.add_development_dependency 'minitest-reporters'
27
+ s.add_development_dependency 'mocha'
28
+ s.add_development_dependency 'faker'
29
+ s.add_development_dependency 'factory_girl'
30
+ s.add_development_dependency 'webmock'
31
+ s.add_development_dependency 'sdoc-templates-42floors'
30
32
 
31
33
  # Runtime
32
- s.add_runtime_dependency 'activesupport'
33
- # the gem provides factories, so this is required as a runtime dependency
34
- s.add_runtime_dependency 'faker'
35
- s.add_runtime_dependency 'factory_girl'
36
- s.add_runtime_dependency 'yajl-ruby'
37
- s.add_runtime_dependency 'rest-client'
38
-
34
+ s.add_runtime_dependency 'sunstone'
39
35
  end
@@ -0,0 +1,55 @@
1
+ require 'test_helper'
2
+
3
+ class MLS::AttributeTest < Minitest::Test
4
+
5
+ test "::new(NAME) sets @name to NAME" do
6
+ attribute = MLS::Attribute.new("name")
7
+ assert_equal "name", attribute.name
8
+ end
9
+
10
+ test "::new(NAME) sets @options to defaults" do
11
+ attribute = MLS::Attribute.new("name")
12
+ assert_equal MLS::Attribute::DEFAULT_OPTIONS, attribute.options
13
+ end
14
+
15
+ test "::new(NAME) sets @instance_variable_name" do
16
+ attribute = MLS::Attribute.new("name")
17
+ assert_equal "@name", attribute.instance_variable_name
18
+ end
19
+
20
+
21
+ test "::new(NAME) sets @default to nil" do
22
+ attribute = MLS::Attribute.new("name")
23
+ assert_equal nil, attribute.default
24
+ end
25
+
26
+ test "::new(NAME, :default => N) sets @default to N" do
27
+ attribute = MLS::Attribute.new("name", :default => 'N')
28
+ assert_equal 'N', attribute.default
29
+ end
30
+
31
+ test "::new(NAME) sets @reader_visibility to :public" do
32
+ attribute = MLS::Attribute.new("name")
33
+ assert_equal :public, attribute.reader_visibility
34
+ end
35
+
36
+ test "::new(NAME, :reader => :private) sets @reader_visibility to :private" do
37
+ attribute = MLS::Attribute.new("name", :reader => :private)
38
+ assert_equal :private, attribute.reader_visibility
39
+ end
40
+
41
+ test "::new(NAME) sets @writer_visibility to :public" do
42
+ attribute = MLS::Attribute.new("name")
43
+ assert_equal :public, attribute.writer_visibility
44
+ end
45
+
46
+ test "::new(NAME, :writer => :private) sets @writer_visibility to :private" do
47
+ attribute = MLS::Attribute.new("name", :writer => :private)
48
+ assert_equal :private, attribute.writer_visibility
49
+ end
50
+
51
+ test "::demodulized_names caches hash" do
52
+ assert_equal MLS::Attribute.demodulized_names.object_id, MLS::Attribute.demodulized_names.object_id
53
+ end
54
+
55
+ end
@@ -0,0 +1,31 @@
1
+ # require 'test_helper'
2
+ #
3
+ # class TestResource < MLS::Resource
4
+ # end
5
+ #
6
+ # class MLS::ResourceTest < Minitest::Test
7
+ #
8
+ # test "subclasses extend MLS::Model" do
9
+ # assert TestResource.kind_of?(MLS::Model)
10
+ # end
11
+ #
12
+ # test ""
13
+ #
14
+ # def test_instance_methods
15
+ # resource = TestResource.new
16
+ #
17
+ # assert resource.respond_to?(:new_record?)
18
+ # assert resource.respond_to?(:persisted?)
19
+ # assert resource.respond_to?(:save)
20
+ #
21
+ # assert resource.respond_to?(:attributes)
22
+ # assert resource.respond_to?(:set_default_values)
23
+ # assert resource.respond_to?(:update_attributes)
24
+ #
25
+ # assert resource.respond_to?(:to_hash)
26
+ # assert resource.respond_to?(:to_key)
27
+ # end
28
+ #
29
+ # test 'save returns true || false'
30
+ #
31
+ # end