mits 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +9 -0
  3. data/{LICENSE.txt → LICENSE} +0 -0
  4. data/README.md +34 -16
  5. data/lib/mits/document.rb +35 -0
  6. data/lib/mits/entities/address.rb +16 -0
  7. data/lib/mits/entities/amenity.rb +8 -0
  8. data/lib/mits/entities/company.rb +11 -0
  9. data/lib/mits/entities/deposit.rb +11 -0
  10. data/lib/mits/entities/fees.rb +15 -0
  11. data/lib/mits/entities/file.rb +16 -0
  12. data/lib/mits/entities/pet.rb +11 -0
  13. data/lib/mits/entities/pet_policy.rb +15 -0
  14. data/lib/mits/entities/property.rb +20 -0
  15. data/lib/mits/entities/unit.rb +11 -0
  16. data/lib/mits/mapper.rb +48 -0
  17. data/lib/mits/mappers/address_mapper.rb +29 -0
  18. data/lib/mits/mappers/amenities_mapper.rb +14 -0
  19. data/lib/mits/mappers/company_mapper.rb +11 -0
  20. data/lib/mits/mappers/deposit_mapper.rb +24 -0
  21. data/lib/mits/mappers/fees_mapper.rb +15 -0
  22. data/lib/mits/mappers/files_mapper.rb +19 -0
  23. data/lib/mits/mappers/pet_policy_mapper.rb +28 -0
  24. data/lib/mits/mappers/property_mapper.rb +41 -0
  25. data/lib/mits/mappers/units_mapper.rb +22 -0
  26. data/lib/mits/saxerator_ext.rb +29 -0
  27. data/lib/mits/version.rb +2 -2
  28. data/lib/mits.rb +9 -3
  29. data/mits.gemspec +13 -6
  30. data/spec/fixtures/mits.xml +396 -0
  31. data/spec/fixtures/property.yml +205 -0
  32. data/spec/lib/mits/document_spec.rb +23 -0
  33. data/spec/lib/mits/entities/address_spec.rb +16 -0
  34. data/spec/lib/mits/entities/amenity_spec.rb +8 -0
  35. data/spec/lib/mits/entities/company_spec.rb +0 -0
  36. data/spec/lib/mits/entities/deposit_spec.rb +11 -0
  37. data/spec/lib/mits/entities/fees_spec.rb +15 -0
  38. data/spec/lib/mits/entities/file_spec.rb +17 -0
  39. data/spec/lib/mits/entities/pet_policy_spec.rb +14 -0
  40. data/spec/lib/mits/entities/pet_spec.rb +12 -0
  41. data/spec/lib/mits/entities/property_spec.rb +20 -0
  42. data/spec/lib/mits/entities/unit_spec.rb +11 -0
  43. data/spec/lib/mits/mapper_spec.rb +180 -0
  44. data/spec/spec_helper.rb +22 -0
  45. metadata +147 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d505939145db141c682033bbf5d3fd1ef8062be3
4
- data.tar.gz: f130e83001a8be5634087fec84f6063ed6fa547d
3
+ metadata.gz: 9e3d066755e4fd3763ed195996832b597c6c559e
4
+ data.tar.gz: b9ad8637001201a6b12713c373971461c23cba9f
5
5
  SHA512:
6
- metadata.gz: baa3aa9da9b2b316eb3cd9ff74592c00e67499029bcffc153bd4193944aae24ddfd2df47bdeb8d1e337813ecebcdc032a5963229e518d22dbf8a07d15757b73c
7
- data.tar.gz: 004c18108965e715d0eeecaa1b6aee85d3e7ca25426c593ebf0cf008babca1e19a2ecffd7c705b4c1e880886f6594caa750540302ce83f414515e05eee7840ee
6
+ metadata.gz: 97d002c90c6ada433bf6a5bb5049ae129ecfa394c86036833f258aacc4bf3f5c3ed92f7c1d945d63801fddf04a7c5c04aec8079e88cfef17548f3fc6e1ce24b9
7
+ data.tar.gz: e917486f219ab2a63e3bdf52d5c77574bcbc6ee4021931295e5178281a8e34fe59d7037f35dbc1b0f7952fe683f81e8481b83d08c1c51f260958040a2c481bac
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.1
4
+ - 2.0.0
5
+ - ruby-head
6
+ script: bundle exec rspec
7
+ matrix:
8
+ allow_failures:
9
+ - rvm: ruby-head
File without changes
data/README.md CHANGED
@@ -1,31 +1,49 @@
1
- # Mits
1
+ # MITS
2
2
 
3
- TODO: Write a gem description
3
+ A SAX powered reader for [Multifamily Information and Transactions Standard \(MITS\)](http://www.mitsproject.org/) compatible documents.
4
+
5
+ Currently supporting MITS __4.1__.
6
+
7
+ [![Gem Version](https://badge.fury.io/rb/mits.png)](https://rubygems.org/gems/mits) [![Build Status](https://travis-ci.org/doomspork/mits.svg?branch=master)](https://travis-ci.org/doomspork/mits) [![Code Climate](https://codeclimate.com/github/doomspork/mits/badges/gpa.svg)](https://codeclimate.com/github/doomspork/mits) [![Coverage Status](https://coveralls.io/repos/doomspork/mits/badge.png?branch=master)](https://coveralls.io/r/doomspork/mits?branch=master) [![Dependency Status](https://gemnasium.com/doomspork/mits.svg)](https://gemnasium.com/doomspork/mits)
4
8
 
5
9
  ## Installation
6
10
 
7
- Add this line to your application's Gemfile:
11
+ gem install mits
12
+
13
+ ## Getting Started
14
+
15
+ Create a `MITS::Document` with a local filepath or URL:
8
16
 
9
17
  ```ruby
10
- gem 'mits'
18
+ document = MITS::Document.new('/example/path/mits_compatible_feed.xml')
11
19
  ```
12
20
 
13
- And then execute:
21
+ Iterating over properties is easy:
14
22
 
15
- $ bundle
16
-
17
- Or install it yourself as:
23
+ ```ruby
24
+ document.properties do |property|
25
+ puts "#{property.name} now available online at #{property.website}"
26
+ end
27
+ ```
18
28
 
19
- $ gem install mits
29
+ The `#properties` method returns a `Enumerator` if no block is provided:
20
30
 
21
- ## Usage
31
+ ```ruby
22
32
 
23
- TODO: Write usage instructions here
33
+ document.properties.each_with_object([]) do |property, arr|
34
+ # Only include properties with 2 or more units
35
+ arr.push(property) if property.units.size > 2
36
+ end
37
+ ```
24
38
 
25
39
  ## Contributing
26
40
 
27
- 1. Fork it ( https://github.com/[my-github-username]/mits/fork )
28
- 2. Create your feature branch (`git checkout -b my-new-feature`)
29
- 3. Commit your changes (`git commit -am 'Add some feature'`)
30
- 4. Push to the branch (`git push origin my-new-feature`)
31
- 5. Create a new Pull Request
41
+ Feedback, feature requests, and fixes are welcome. Please make appropriate use of [Issues](https://github.com/doomspork/mits/issues) and [Pull Requests](https://github.com/doomspork/mits/pulls). All code should have accompanying tests.
42
+
43
+ ## Author
44
+
45
+ MITS is written and maintained by [@doomspork](http://github.com/doomspork) as part of [CityLeash](https://cityleash.com).
46
+
47
+ ## License
48
+
49
+ Please see [LICENSE](https://github.com/doomspork/mits/blob/master/LICENSE) for licensing details.
@@ -0,0 +1,35 @@
1
+ module MITS
2
+ class Document
3
+ attr_reader :parser
4
+
5
+ def initialize(url)
6
+ @parser = ::Saxerator.parser(open(url)) do |c|
7
+ c.put_attributes_in_hash!
8
+ c.symbolize_keys!
9
+ end
10
+ end
11
+
12
+ def properties
13
+ return enum_for(:properties) unless block_given?
14
+
15
+ physical_property.for_tag(:Property).each do |tag|
16
+ yield Mapper.property(tag)
17
+ end
18
+ end
19
+
20
+ def companies
21
+ return enum_for(:companies) unless block_given?
22
+
23
+ physical_property.within(:Management).within(:PropertyContacts).each do |tag|
24
+ yield Mapper.company(tag)
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def physical_property
31
+ parser.within(:PhysicalProperty)
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ module MITS
2
+ class Address
3
+ include SimpleObjects::Base
4
+
5
+ attribute :address1
6
+ attribute :address2
7
+ attribute :city
8
+ attribute :country
9
+ attribute :description
10
+ attribute :latitude
11
+ attribute :longitude
12
+ attribute :postal_code
13
+ attribute :state
14
+ attribute :type
15
+ end
16
+ end
@@ -0,0 +1,8 @@
1
+ module MITS
2
+ class Amenity
3
+ include SimpleObjects::Base
4
+
5
+ attribute :description
6
+ attribute :type
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ module MITS
2
+ class Company
3
+ include SimpleObjects::Base
4
+
5
+ attribute :id
6
+ attribute :name
7
+ attribute :address
8
+ attribute :website
9
+ attribute :logo
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module MITS
2
+ class Deposit
3
+ include SimpleObjects::Base
4
+
5
+ attribute :amount
6
+ attribute :description
7
+ attribute :percent_refundable
8
+ attribute :portion_refundable
9
+ attribute :type
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module MITS
2
+ class Fees
3
+ include SimpleObjects::Base
4
+
5
+ attribute :admin_fee
6
+ attribute :application_fee
7
+ attribute :broker_fee
8
+ attribute :late_fee_per_day
9
+ attribute :late_min_fee
10
+ attribute :late_percent
11
+ attribute :late_type
12
+ attribute :non_refundable_hold_fee
13
+ attribute :prorate_type
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ module MITS
2
+ class File
3
+ include SimpleObjects::Base
4
+
5
+ attribute :active
6
+ attribute :caption
7
+ attribute :description
8
+ attribute :format
9
+ attribute :height
10
+ attribute :id
11
+ attribute :name
12
+ attribute :rank
13
+ attribute :source
14
+ attribute :width
15
+ end
16
+ end
@@ -0,0 +1,11 @@
1
+ module MITS
2
+ class Pet
3
+ include SimpleObjects::Base
4
+
5
+ attribute :count
6
+ attribute :description
7
+ attribute :size
8
+ attribute :type
9
+ attribute :weight
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module MITS
2
+ class PetPolicy
3
+ include SimpleObjects::Base
4
+
5
+ attribute :allowed
6
+ attribute :care
7
+ attribute :deposit
8
+ attribute :fee
9
+ attribute :pets
10
+ attribute :rent
11
+ attribute :restrictions
12
+
13
+ alias_method :allowed?, :allowed
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ module MITS
2
+ class Property
3
+ include SimpleObjects::Base
4
+
5
+ attribute :address
6
+ attribute :amenities
7
+ attribute :company_id
8
+ attribute :deposit
9
+ attribute :description
10
+ attribute :fees
11
+ attribute :files
12
+ attribute :id
13
+ attribute :name
14
+ attribute :pet_policy
15
+ attribute :summary
16
+ attribute :type
17
+ attribute :units
18
+ attribute :website
19
+ end
20
+ end
@@ -0,0 +1,11 @@
1
+ module MITS
2
+ class Unit
3
+ include SimpleObjects::Base
4
+
5
+ attribute :bathrooms
6
+ attribute :bedrooms
7
+ attribute :name
8
+ attribute :rent
9
+ attribute :sqft
10
+ end
11
+ end
@@ -0,0 +1,48 @@
1
+ require 'mits/entities/address'
2
+ require 'mits/entities/amenity'
3
+ require 'mits/entities/company'
4
+ require 'mits/entities/deposit'
5
+ require 'mits/entities/fees'
6
+ require 'mits/entities/file'
7
+ require 'mits/entities/pet'
8
+ require 'mits/entities/pet_policy'
9
+ require 'mits/entities/property'
10
+ require 'mits/entities/unit'
11
+
12
+ require 'mits/mappers/address_mapper'
13
+ require 'mits/mappers/amenities_mapper'
14
+ require 'mits/mappers/company_mapper'
15
+ require 'mits/mappers/deposit_mapper'
16
+ require 'mits/mappers/fees_mapper'
17
+ require 'mits/mappers/files_mapper'
18
+ require 'mits/mappers/pet_policy_mapper'
19
+ require 'mits/mappers/property_mapper'
20
+ require 'mits/mappers/units_mapper'
21
+
22
+ module MITS
23
+ module Mapper
24
+ extend AddressMapper
25
+ extend AmenitiesMapper
26
+ extend CompanyMapper
27
+ extend DepositMapper
28
+ extend FeesMapper
29
+ extend FilesMapper
30
+ extend PetPolicyMapper
31
+ extend PropertyMapper
32
+ extend UnitsMapper
33
+
34
+ extend self
35
+
36
+ protected
37
+
38
+ def bool(value)
39
+ value == 'true'
40
+ end
41
+
42
+ def try(value, method)
43
+ return nil unless value
44
+ value.send(method)
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,29 @@
1
+ module MITS
2
+ module AddressMapper
3
+ def address(tag, secondary_tag = nil)
4
+ attrs = address_attributes(tag)
5
+
6
+ if secondary_tag
7
+ attrs[:latitude] = try(secondary_tag[:Latitude], :to_f)
8
+ attrs[:longitude] = try(secondary_tag[:Longitude], :to_f)
9
+ end
10
+
11
+ Address.new(attrs)
12
+ end
13
+
14
+ private
15
+
16
+ def address_attributes(tag)
17
+ {
18
+ type: tag[:AddressType],
19
+ description: tag[:Description],
20
+ address1: tag[:AddressLine1],
21
+ address2: tag[:AddressLine2],
22
+ city: tag[:City],
23
+ state: tag[:State],
24
+ postal_code: tag[:PostalCode],
25
+ country: tag[:Country],
26
+ }
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,14 @@
1
+ module MITS
2
+ module AmenitiesMapper
3
+ def amenities(tags)
4
+ if tags
5
+ tags = [tags] unless tags.is_a? Array
6
+ tags.map { |tag| amenity(tag) }
7
+ end
8
+ end
9
+
10
+ def amenity(tag)
11
+ Amenity.new(description: tag[:Description], type: tag[:AmenityType])
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,11 @@
1
+ module MITS
2
+ module CompanyMapper
3
+ def company(tag)
4
+ Company.new(address: address(tag[:Address]),
5
+ id: tag[:Identification][:IDValue],
6
+ logo: tag[:Logo],
7
+ name: tag[:CompanyName],
8
+ website: tag[:Website])
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ module MITS
2
+ module DepositMapper
3
+ def deposit(tag)
4
+ Deposit.new(amount: deposit_amount(tag[:Amount][:ValueRange]),
5
+ description: tag[:Description],
6
+ percent_refundable: try(tag[:PercentRefundable], :to_f),
7
+ portion_refundable: try(tag[:PortionRefundable], :to_f),
8
+ type: tag[:DepositType])
9
+ end
10
+
11
+ private
12
+
13
+ def deposit_amount(tag)
14
+ if tag[:Exact]
15
+ amount = tag[:Exact].to_f
16
+ else
17
+ min = tag[:Min].to_f
18
+ max = tag[:Max].to_f
19
+ amount = Range.new(min, max)
20
+ end
21
+ amount
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ module MITS
2
+ module FeesMapper
3
+ def fees(tag)
4
+ Fees.new(admin_fee: try(tag[:AdminFee], :to_f),
5
+ application_fee: try(tag[:ApplicationFee], :to_f),
6
+ broker_fee: try(tag[:BrokerFee], :to_f),
7
+ late_fee_per_day: try(tag[:LateFeePerDay], :to_f),
8
+ late_min_fee: try(tag[:LateMinFee], :to_f),
9
+ late_percent: try(tag[:LatePercent], :to_f),
10
+ late_type: tag[:LateType],
11
+ non_refundable_hold_fee: try(tag[:NonRefundableHoldFee], :to_f),
12
+ prorate_type: tag[:ProrateType])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ module MITS
2
+ module FilesMapper
3
+ def files(tags)
4
+ tags = [tags] unless tags.is_a? Array
5
+ tags.map do |tag|
6
+ File.new(active: bool(tag[:Active]),
7
+ caption: tag[:Caption],
8
+ description: tag[:Description],
9
+ format: tag[:Format],
10
+ height: try(tag[:Height], :to_i),
11
+ id: tag[:FileID],
12
+ name: tag[:Name],
13
+ rank: tag[:Rank],
14
+ source: tag[:Src],
15
+ width: tag[:Width])
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module MITS
2
+ module PetPolicyMapper
3
+ def pet_policy(tag)
4
+ if bool(tag[:Allowed])
5
+ PetPolicy.new(allowed: true,
6
+ care: bool(tag[:PetCare]),
7
+ deposit: try(tag[:Deposit], :to_f),
8
+ fee: try(tag[:Fee], :to_f),
9
+ pets: pets(tag[:Pets]),
10
+ rent: try(tag[:Rent], :to_f),
11
+ restrictions: tag[:Restrictions])
12
+ else
13
+ PetPolicy.new(allowed: false)
14
+ end
15
+ end
16
+
17
+ def pets(tags)
18
+ tags = [tags] unless tags.is_a? Array
19
+ tags.map do |tag|
20
+ Pet.new(count: tag[:Count].to_i,
21
+ description: tag[:Description],
22
+ size: tag[:Size],
23
+ weight: tag[:Weight],
24
+ type: tag[:PetType])
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,41 @@
1
+ module MITS
2
+ module PropertyMapper
3
+ def property(tag)
4
+ basics = property_basics(tag)
5
+ details = property_details(tag)
6
+ Property.new(basics.merge(details))
7
+ end
8
+
9
+ private
10
+
11
+ def property_basics(tag)
12
+ propId = tag[:PropertyID]
13
+ {
14
+ company_id: company_id(propId[:Identification]),
15
+ description: tag[:Information][:LongDescription],
16
+ id: tag[:IDValue],
17
+ name: propId[:MarketingName],
18
+ summary: tag[:Information][:ShortDescription],
19
+ type: tag[:ILS_Identification][:ILS_IdentificationType],
20
+ website: propId[:WebSite]
21
+ }
22
+ end
23
+
24
+ def property_details(tag)
25
+ {
26
+ address: address(tag[:PropertyID][:Address], tag[:ILS_Identification]),
27
+ amenities: amenities(tag[:ILS_Unit][:Amenity]),
28
+ deposit: deposit(tag[:Deposit]),
29
+ fees: fees(tag[:Fee]),
30
+ files: files(tag[:File]),
31
+ pet_policy: pet_policy(tag[:Policy][:Pet]),
32
+ units: units(tag[:ILS_Unit][:Units][:Unit])
33
+ }
34
+ end
35
+
36
+ def company_id(tags)
37
+ tag = tags.find { |t| t[:IDType].downcase == 'company' }
38
+ tag[:IDValue] if tag
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ module MITS
2
+ module UnitsMapper
3
+ def units(tags)
4
+ tags = [tags] unless tags.is_a? Array
5
+ tags.map do |tag|
6
+ Unit.new(bathrooms: try(tag[:UnitBathrooms], :to_f),
7
+ bedrooms: try(tag[:UnitBedrooms], :to_f),
8
+ name: tag[:MarketingName],
9
+ rent: try(tag[:UnitRent], :to_f),
10
+ sqft: unit_sqft(tag))
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ def unit_sqft(tag)
17
+ min = tag[:MinSquareFeet]
18
+ max = tag[:MaxSquareFeet]
19
+ Range.new(min.to_i, max.to_i)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,29 @@
1
+ module Saxerator
2
+ module Builder
3
+ class HashElement < Hash
4
+ def deep_hash
5
+ self.reduce({}) do |memo, (key, value)|
6
+ as_hash = if value.is_a? Array
7
+ value.map { |v| try_hash(v) }
8
+ else
9
+ try_hash(value)
10
+ end
11
+ memo[key] = as_hash
12
+ memo
13
+ end
14
+ end
15
+
16
+ def try_hash(val)
17
+ if val.is_a? EmptyElement
18
+ nil
19
+ elsif val.respond_to? :deep_hash
20
+ val.deep_hash
21
+ elsif val.respond_to? :to_h
22
+ val.to_h
23
+ else
24
+ val
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
data/lib/mits/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module Mits
2
- VERSION = "0.0.1"
1
+ module MITS
2
+ VERSION = '0.1.0'
3
3
  end
data/lib/mits.rb CHANGED
@@ -1,5 +1,11 @@
1
- require "mits/version"
1
+ require 'open-uri'
2
+ require 'saxerator'
3
+ require 'simple_objects'
2
4
 
3
- module Mits
4
- # Your code goes here...
5
+ require 'mits/document'
6
+ require 'mits/mapper'
7
+ require 'mits/saxerator_ext'
8
+ require 'mits/version'
9
+
10
+ module MITS
5
11
  end
data/mits.gemspec CHANGED
@@ -5,11 +5,11 @@ require 'mits/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'mits'
8
- spec.version = Mits::VERSION
8
+ spec.version = MITS::VERSION
9
9
  spec.authors = ['Sean Callan']
10
10
  spec.email = ['seancallan@gmail.com']
11
- spec.summary = 'A SAX powered MITS reader.'
12
- spec.description = ''
11
+ spec.summary = 'A SAX powered MITS reader for Ruby.'
12
+ spec.description = 'A SAX powered Multifamily Information and Transactions Standard (MITS) reader for Ruby.'
13
13
  spec.homepage = 'https://github.com/doomspork/mits'
14
14
  spec.license = 'MIT'
15
15
 
@@ -18,7 +18,14 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'simple_objects', '~> 0.1'
22
- spec.add_development_dependency 'bundler', '~> 1.7'
23
- spec.add_development_dependency 'rake', '~> 10.0'
21
+ spec.add_dependency 'simple_objects', '~> 1.1'
22
+ spec.add_dependency 'saxerator', '~> 0.9.5'
23
+
24
+ spec.add_development_dependency 'bundler', '~> 1.7'
25
+ spec.add_development_dependency 'coveralls', '~> 0.7'
26
+ spec.add_development_dependency 'pry', '~> 0.10'
27
+ spec.add_development_dependency 'pry-byebug', '~> 2.0'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rspec', '~> 3.1'
30
+ spec.add_development_dependency 'simplecov', '~> 0.9'
24
31
  end