├── .ruby-version
├── .gitignore
├── Gemfile
├── autotest
└── discover.rb
├── lib
├── highrise
│ ├── version.rb
│ ├── comment.rb
│ ├── group.rb
│ ├── membership.rb
│ ├── deal_category.rb
│ ├── task_category.rb
│ ├── recording.rb
│ ├── account.rb
│ ├── tag.rb
│ ├── email.rb
│ ├── note.rb
│ ├── subject_data.rb
│ ├── task.rb
│ ├── deal.rb
│ ├── party.rb
│ ├── company.rb
│ ├── subject_field.rb
│ ├── user.rb
│ ├── kase.rb
│ ├── taggable.rb
│ ├── person.rb
│ ├── searchable.rb
│ ├── subject.rb
│ ├── base.rb
│ ├── custom_fields.rb
│ └── pagination.rb
└── highrise.rb
├── spec
├── highrise
│ ├── group_spec.rb
│ ├── comment_spec.rb
│ ├── membership_spec.rb
│ ├── recording_spec.rb
│ ├── pagination_spec.rb
│ ├── searchable_spec.rb
│ ├── taggable_spec.rb
│ ├── account_spec.rb
│ ├── task_spec.rb
│ ├── email_spec.rb
│ ├── note_spec.rb
│ ├── deal_category_spec.rb
│ ├── task_category_spec.rb
│ ├── tag_spec.rb
│ ├── user_spec.rb
│ ├── party_spec.rb
│ ├── searchable_behavior.rb
│ ├── deal_spec.rb
│ ├── taggable_behavior.rb
│ ├── kase_spec.rb
│ ├── subject_data_spec.rb
│ ├── subject_field_spec.rb
│ ├── subject_spec.rb
│ ├── base_spec.rb
│ ├── pagination_behavior.rb
│ ├── company_spec.rb
│ └── person_spec.rb
└── spec_helper.rb
├── examples
├── config_initializers_highrise.rb
├── sample.rb
└── extending.rb
├── Rakefile
├── MIT-LICENSE
├── highrise.gemspec.erb
├── certs
└── gem-public_cert.pem
├── Gemfile.lock
├── README.md
└── highrise.gemspec
/.ruby-version:
--------------------------------------------------------------------------------
1 | ruby-2.3.1
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | pkg/**
2 | .rvmrc
3 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/autotest/discover.rb:
--------------------------------------------------------------------------------
1 | Autotest.add_discovery { "rspec2" }
2 |
--------------------------------------------------------------------------------
/lib/highrise/version.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | VERSION = "3.2.3"
3 | end
--------------------------------------------------------------------------------
/lib/highrise/comment.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Comment < Base; end
3 | end
--------------------------------------------------------------------------------
/lib/highrise/group.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Group < Base; end
3 | end
--------------------------------------------------------------------------------
/lib/highrise/membership.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Membership < Base; end
3 | end
--------------------------------------------------------------------------------
/lib/highrise/deal_category.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class DealCategory < Base; end
3 | end
--------------------------------------------------------------------------------
/lib/highrise/task_category.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class TaskCategory < Base; end
3 | end
--------------------------------------------------------------------------------
/lib/highrise/recording.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Recording < Base
3 | include Pagination
4 | end
5 | end
--------------------------------------------------------------------------------
/spec/highrise/group_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Group do
4 | it { should be_a_kind_of Highrise::Base }
5 | end
6 |
--------------------------------------------------------------------------------
/spec/highrise/comment_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Comment do
4 | it { should be_a_kind_of Highrise::Base }
5 | end
6 |
--------------------------------------------------------------------------------
/spec/highrise/membership_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Membership do
4 | it { should be_a_kind_of Highrise::Base }
5 | end
6 |
--------------------------------------------------------------------------------
/lib/highrise/account.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Account < Base
3 | def self.me
4 | find(:one, :from => "/account.xml")
5 | end
6 | end
7 | end
--------------------------------------------------------------------------------
/examples/config_initializers_highrise.rb:
--------------------------------------------------------------------------------
1 | if Rails.env != 'test' then
2 | Highrise::Base.site = 'https://example.com.i'
3 | Highrise::Base.user = 'my_fancy_auth_token'
4 | end
--------------------------------------------------------------------------------
/spec/highrise/recording_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Recording do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it_should_behave_like "a paginated class"
7 | end
--------------------------------------------------------------------------------
/lib/highrise/tag.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Tag < Base
3 | def ==(object)
4 | (object.instance_of?(self.class) && object.id == self.id && object.name == self.name)
5 | end
6 | end
7 | end
--------------------------------------------------------------------------------
/examples/sample.rb:
--------------------------------------------------------------------------------
1 | require 'highrise'
2 | require 'pp'
3 |
4 | Highrise::Base.site = 'https://yoursite.highrisehq.com'
5 | Highrise::Base.user = 'xxx'
6 |
7 | @tags = Highrise::Tag.find(:all)
8 |
9 | pp @tags
--------------------------------------------------------------------------------
/lib/highrise/email.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Email < Base
3 | include Pagination
4 |
5 | def comments
6 | Comment.find(:all, :from => "/emails/#{id}/comments.xml")
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/lib/highrise/note.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Note < Base
3 | include Pagination
4 |
5 | def comments
6 | Comment.find(:all, :from => "/notes/#{id}/comments.xml")
7 | end
8 | end
9 | end
--------------------------------------------------------------------------------
/lib/highrise/subject_data.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class SubjectData < Base
3 | def==other
4 | attributes["value"] == other.attributes["value"] &&
5 | attributes["subject_field_label"] == other.attributes["subject_field_label"]
6 | end
7 | end
8 | end
--------------------------------------------------------------------------------
/spec/highrise/pagination_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Pagination do
4 | class TestClass < Highrise::Base; include Highrise::Pagination; end
5 | subject { TestClass.new }
6 |
7 | it_should_behave_like "a paginated class"
8 | end
9 |
--------------------------------------------------------------------------------
/spec/highrise/searchable_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Searchable do
4 | class TestClass < Highrise::Base; include Highrise::Searchable; end
5 | subject { TestClass.new }
6 |
7 | it_should_behave_like "a searchable class"
8 | end
9 |
--------------------------------------------------------------------------------
/spec/highrise/taggable_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Taggable do
4 | class TestClass < Highrise::Base; include Highrise::Taggable; end
5 |
6 | subject { TestClass.new }
7 |
8 | it_should_behave_like "a taggable class"
9 | end
10 |
--------------------------------------------------------------------------------
/lib/highrise/task.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Task < Base
3 | # find(:all, :from => :upcoming)
4 | # find(:all, :from => :assigned)
5 | # find(:all, :from => :completed)
6 |
7 | def complete!
8 | load_attributes_from_response(post(:complete))
9 | end
10 | end
11 | end
--------------------------------------------------------------------------------
/spec/highrise/account_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Account do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it ".me" do
7 | Highrise::Account.should_receive(:find).with(:one, {:from => "/account.xml"}).and_return(subject)
8 | Highrise::Account.me.should == subject
9 | end
10 | end
11 |
--------------------------------------------------------------------------------
/lib/highrise/deal.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Deal < Subject
3 | include Pagination
4 | def update_status(status)
5 | raise ArgumentError, "status must be one of 'pending', 'won', or 'lost'" unless %w[pending won lost].include?(status)
6 | self.put(:status, :status => {:name => status})
7 | end
8 | end
9 | end
10 |
--------------------------------------------------------------------------------
/lib/highrise/party.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Party < Base
3 | def self.recently_viewed
4 | find(:all, :from => "/parties/recently_viewed.xml")
5 | end
6 |
7 | def self.deletions_since(time)
8 | find(:all, :from => "/parties/deletions.xml", :params => { :since => time.utc.strftime("%Y%m%d%H%M%S") })
9 | end
10 | end
11 | end
--------------------------------------------------------------------------------
/spec/highrise/task_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Task do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it "#complete!" do
7 | subject.should_receive(:load_attributes_from_response).with("post")
8 | subject.should_receive(:post).with(:complete).and_return("post")
9 | subject.complete!
10 | end
11 | end
12 |
--------------------------------------------------------------------------------
/lib/highrise/company.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Company < Subject
3 | include Pagination
4 | include Taggable
5 | include Searchable
6 | include CustomFields
7 |
8 | def people
9 | Person.find_all_across_pages(:from => "/companies/#{id}/people.xml")
10 | end
11 |
12 | def label
13 | 'Party'
14 | end
15 | end
16 | end
--------------------------------------------------------------------------------
/spec/highrise/email_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Email do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it_should_behave_like "a paginated class"
7 |
8 | it "#comments" do
9 | subject.should_receive(:id).and_return(1)
10 | Highrise::Comment.should_receive(:find).with(:all, {:from=>"/emails/1/comments.xml"}).and_return("comments")
11 | subject.comments.should == "comments"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/highrise/note_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Note do
4 | subject { Highrise::Note.new(:id => 1) }
5 |
6 | it { should be_a_kind_of Highrise::Base }
7 |
8 | it_should_behave_like "a paginated class"
9 |
10 | it "#comments" do
11 | Highrise::Comment.should_receive(:find).with(:all, {:from=>"/notes/1/comments.xml"}).and_return("comments")
12 | subject.comments.should == "comments"
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/spec/spec_helper.rb:
--------------------------------------------------------------------------------
1 | require 'bundler'
2 | Bundler.setup
3 |
4 | require File.join(File.dirname(__FILE__), '/../lib/highrise')
5 |
6 | Highrise::Base.user = ENV['HIGHRISE_USER'] || 'x'
7 | Highrise::Base.oauth_token = ENV['HIGHRISE_TOKEN'] || 'TOKEN'
8 | Highrise::Base.site = ENV['HIGHRISE_SITE'] || 'https://www.example.com'
9 |
10 | require 'highrise/pagination_behavior'
11 | require 'highrise/searchable_behavior'
12 | require 'highrise/taggable_behavior'
13 | require 'active_resource/http_mock'
14 |
15 |
--------------------------------------------------------------------------------
/spec/highrise/deal_category_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::DealCategory do
4 | subject { Highrise::DealCategory.new(:id => 1, :name => "Deal Category") }
5 |
6 | it { should be_a_kind_of Highrise::Base }
7 |
8 | it ".find_by_name" do
9 | deal_category = Highrise::DealCategory.new(:id => 2, :name => "Another Deal Category")
10 | Highrise::DealCategory.should_receive(:find).with(:all).and_return([deal_category, subject])
11 | Highrise::DealCategory.find_by_name("Deal Category").should == subject
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/spec/highrise/task_category_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::TaskCategory do
4 | subject { Highrise::TaskCategory.new(:id => 1, :name => "Task Category") }
5 |
6 | it { should be_a_kind_of Highrise::Base }
7 |
8 | it ".find_by_name" do
9 | task_category = Highrise::TaskCategory.new(:id => 2, :name => "Another Task Category")
10 | Highrise::TaskCategory.should_receive(:find).with(:all).and_return([task_category, subject])
11 | Highrise::TaskCategory.find_by_name("Task Category").should == subject
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/highrise/subject_field.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class SubjectField < Base
3 |
4 | def initialize(attributes = {}, persisted = false)
5 | super
6 | @use_cache = false
7 | end
8 |
9 | def self.use_cache(use_cache = true)
10 | @use_cache = use_cache
11 | end
12 |
13 | def self.find_every(options)
14 | if @use_cache
15 | @subject_field_cache ||= super
16 | else
17 | super
18 | end
19 | end
20 |
21 | def self.invalidate_cache
22 | @subject_field_cache = nil
23 | end
24 | end
25 | end
26 |
27 |
--------------------------------------------------------------------------------
/spec/highrise/tag_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Tag do
4 | subject { Highrise::Tag.new(:id => 1, :name => "Name") }
5 |
6 | it { should be_a_kind_of Highrise::Base }
7 |
8 | it "supports equality" do
9 | tag = Highrise::Tag.new(:id => 1, :name => "Name")
10 | subject.should == tag
11 | end
12 |
13 | it ".find_by_name" do
14 | tag = Highrise::Tag.new(:id => 2, :name => "Next")
15 | Highrise::Tag.should_receive(:find).with(:all).and_return([tag, subject])
16 | Highrise::Tag.find_by_name("Name").should == subject
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/lib/highrise/user.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class User < Base
3 | def join(group)
4 | Membership.create(:user_id => id, :group_id => group.id)
5 | end
6 |
7 | # Permits API-key retrieval using name and password.
8 | # Highrise::User.site = "https://yourcompany.highrise.com"
9 | # Highrise::User.user = "your_user_name"
10 | # Highrise::User.password = "s3kr3t"
11 | # Highrise::User.me.token # contains the API token for "your_user_name"
12 | def self.me
13 | user = User.new()
14 | find(:one, :from => "/me.xml")
15 | end
16 | end
17 | end
--------------------------------------------------------------------------------
/spec/highrise/user_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::User do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it ".me" do
7 | Highrise::User.should_receive(:find).with(:one, {:from => "/me.xml"}).and_return(subject)
8 | Highrise::User.me.should == subject
9 | end
10 |
11 | it "#join" do
12 | group_mock = mock("group")
13 | group_mock.should_receive(:id).and_return(2)
14 | subject.should_receive(:id).and_return(1)
15 | Highrise::Membership.should_receive(:create).with({:user_id=>1, :group_id=>2})
16 | subject.join(group_mock)
17 | end
18 | end
19 |
--------------------------------------------------------------------------------
/spec/highrise/party_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Party do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it ".recently_viewed" do
7 | Highrise::Party.should_receive(:find).with(:all, {:from => '/parties/recently_viewed.xml'})
8 | Highrise::Party.recently_viewed
9 | end
10 |
11 | it ".deletions_since" do
12 | time = Time.parse("Wed Jan 14 15:43:11 -0200 2009")
13 | Highrise::Party.should_receive(:find).with(:all, {:from => '/parties/deletions.xml', :params=>{:since=>"20090114174311"}}).and_return("result")
14 | Highrise::Party.deletions_since(time).should == "result"
15 | end
16 | end
--------------------------------------------------------------------------------
/spec/highrise/searchable_behavior.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "a searchable class" do
2 | it { subject.class.included_modules.should include(Highrise::Searchable) }
3 |
4 | it ".search" do
5 | find_args = {:from => "/#{subject.class.collection_name}/search.xml", :params => {"criteria[email]" => "john.doe@example.com", "criteria[zip]" => "90210"}}
6 | if subject.class.respond_to?(:find_all_across_pages)
7 | subject.class.should_receive(:find_all_across_pages).with(find_args)
8 | else
9 | subject.class.should_receive(:find).with(:all, find_args)
10 | end
11 | subject.class.search(:email => "john.doe@example.com", :zip => "90210")
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/lib/highrise/kase.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Kase < Subject
3 | include Pagination
4 |
5 | def open!
6 | update_attribute(:closed_at, nil)
7 | end
8 |
9 | def close!
10 | update_attribute(:closed_at, Time.now.utc)
11 | end
12 |
13 | def self.open
14 | Kase.find(:all, :from => "/kases/open.xml")
15 | end
16 |
17 | def self.closed
18 | Kase.find(:all, :from => "/kases/closed.xml")
19 | end
20 |
21 | def self.all_open_across_pages
22 | find_all_across_pages(:from => "/kases/open.xml")
23 | end
24 |
25 | def self.all_closed_across_pages
26 | find_all_across_pages(:from => "/kases/closed.xml")
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require 'bundler'
3 | Bundler::GemHelper.install_tasks if File.exist? 'highrise.gemspec'
4 |
5 | require 'rspec/core/rake_task'
6 | require 'erb'
7 |
8 | desc 'Default: run unit tests.'
9 | task :default => :spec
10 |
11 | desc "Run all specs"
12 | RSpec::Core::RakeTask.new do |t|
13 | t.pattern = 'spec/**/*_spec.rb'
14 | t.rspec_opts = ["-c", "-f progress"]
15 | end
16 |
17 | desc 'Generate gemspec'
18 | task :gemspec do
19 | gemspec = 'highrise.gemspec'
20 |
21 | #FileUtils.rm gemspec if File.exist? gemspec
22 | template = ERB.new File.new("#{gemspec}.erb").read
23 |
24 | begin
25 | gemspec_file = File.open(gemspec,'w')
26 | gemspec_file.write template.result(binding)
27 | ensure
28 | gemspec_file.close
29 | end
30 |
31 | puts "done!"
32 | end
--------------------------------------------------------------------------------
/lib/highrise.rb:
--------------------------------------------------------------------------------
1 | require 'highrise/base'
2 | require 'highrise/pagination'
3 | require 'highrise/taggable'
4 | require 'highrise/searchable'
5 | require 'highrise/custom_fields'
6 | require 'highrise/subject'
7 | require 'highrise/comment'
8 | require 'highrise/company'
9 | require 'highrise/email'
10 | require 'highrise/group'
11 | require 'highrise/kase'
12 | require 'highrise/membership'
13 | require 'highrise/note'
14 | require 'highrise/person'
15 | require 'highrise/task'
16 | require 'highrise/user'
17 | require 'highrise/tag'
18 | require 'highrise/deal'
19 | require 'highrise/account'
20 | require 'highrise/deal_category'
21 | require 'highrise/task_category'
22 | require 'highrise/party'
23 | require 'highrise/recording'
24 | require 'highrise/subject_data'
25 | require 'highrise/subject_field'
26 |
--------------------------------------------------------------------------------
/spec/highrise/deal_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Deal do
4 | subject { Highrise::Deal.new(:id => 1) }
5 |
6 | it { should be_a_kind_of Highrise::Subject }
7 |
8 | it ".add_note" do
9 | Highrise::Note.should_receive(:create).with({:body=>"body", :subject_id=>1, :subject_type=>'Deal'}).and_return(mock('note'))
10 | subject.add_note :body=>'body'
11 | end
12 |
13 | describe ".update_status" do
14 | it { expect { subject.update_status("invalid") }.to raise_error(ArgumentError) }
15 |
16 | %w[pending won lost].each do |status|
17 | it "updates status to #{status}" do
18 | subject.should_receive(:put).with(:status, :status => {:name => status})
19 | subject.update_status(status)
20 | end
21 | end
22 | end
23 | end
--------------------------------------------------------------------------------
/lib/highrise/taggable.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | module Taggable
3 |
4 | def tags
5 | unless self.attributes.has_key?("tags")
6 | person_or_company = self.class.find(id)
7 | self.attributes["tags"] = person_or_company.attributes.has_key?("tags") ? person_or_company.tags : []
8 | end
9 | self.attributes["tags"]
10 | end
11 |
12 | def tag!(tag_name)
13 | self.post(:tags, :name => tag_name) unless tag_name.blank?
14 | end
15 |
16 | def untag!(tag_name)
17 | to_delete = self.tags.find{|tag| tag.attributes['name'] == tag_name} unless tag_name.blank?
18 | self.untag_id!(to_delete.attributes['id']) unless to_delete.nil?
19 | end
20 | protected
21 | def untag_id!(tag_id)
22 | self.delete("tags/#{tag_id}")
23 | end
24 | end
25 | end
26 |
--------------------------------------------------------------------------------
/spec/highrise/taggable_behavior.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "a taggable class" do
2 | before(:each) do
3 | (@tags = []).tap do
4 | @tags << Highrise::Tag.new(:name => "cliente", :id => 414578)
5 | @tags << Highrise::Tag.new(:name => "ged", :id => 414580)
6 | @tags << Highrise::Tag.new(:name => "iepc", :id => 414579)
7 | end
8 | end
9 |
10 | it { subject.class.included_modules.should include(Highrise::Taggable) }
11 |
12 | it "#tag!(tag_name)" do
13 | subject.should_receive(:post).with(:tags, :name => "client" ).and_return(true)
14 | subject.tag!("client").should be_true
15 | end
16 |
17 | it "#untag!(tag_name)" do
18 | subject.should_receive(:tags).and_return(@tags)
19 | subject.should_receive(:delete).with("tags/414578").and_return(true)
20 | subject.untag!("cliente").should be_true
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/lib/highrise/person.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Person < Subject
3 | include Pagination
4 | include Taggable
5 | include Searchable
6 | include CustomFields
7 |
8 | def company
9 | Company.find(company_id) if company_id
10 | end
11 |
12 | def name
13 | "#{first_name rescue ''} #{last_name rescue ''}".strip
14 | end
15 |
16 | def address
17 | contact_data.addresses.first
18 | end
19 |
20 | def web_address
21 | contact_data.web_addresses.first
22 | end
23 |
24 | def email_addresses
25 | contact_data.email_addresses.collect { |address| address.address } rescue []
26 | end
27 |
28 | def phone_numbers
29 | contact_data.phone_numbers.collect { |phone_number| phone_number.number } rescue []
30 | end
31 |
32 | def label
33 | 'Party'
34 | end
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/examples/extending.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Example of extending a class when you need to synthesize an attribute.
3 | #
4 | # Adds Highrise::Person.{phone,fax,email} to the Person class inside your
5 | # module
6 | #
7 |
8 | module MyModule
9 | include Highrise
10 |
11 | Highrise::Person.class_eval do
12 | class << self
13 | def lookup(id, list, item, location)
14 | module_eval <<-EOT
15 | def #{id}
16 | contact_data.#{list}.each do |i|
17 | return i.#{item}.strip if i.location == "#{location}"
18 | end
19 | ''
20 | end
21 | EOT
22 | end
23 |
24 | private :lookup
25 | end
26 |
27 | lookup(:phone, 'phone_numbers', 'number', 'Work')
28 | lookup(:fax, 'phone_numbers', 'number', 'Fax')
29 | lookup(:email, 'email_addresses', 'address', 'Work')
30 | end
31 | end
--------------------------------------------------------------------------------
/lib/highrise/searchable.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | module Searchable
3 | def self.included(base)
4 | base.extend(ClassMethods)
5 | end
6 |
7 | module ClassMethods
8 | # List By Search Criteria
9 | # Ex: Highrise::Person.search(:email => "john.doe@example.com", :country => "CA")
10 | # Available criteria are: city, state, country, zip, phone, email
11 | def search(options = {})
12 | search_params = options.inject({}) { |h, (k, v)| h["criteria[#{k}]"] = v; h }
13 | # This might have to be changed in the future if other non-pagable resources become searchable
14 | if self.respond_to?(:find_all_across_pages)
15 | self.find_all_across_pages(:from => "/#{self.collection_name}/search.xml", :params => search_params)
16 | else
17 | self.find(:all, {:from => "/#{self.collection_name}/search.xml", :params => search_params})
18 | end
19 | end
20 | end
21 | end
22 | end
--------------------------------------------------------------------------------
/lib/highrise/subject.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | class Subject < Base
3 | def notes(options={})
4 | options.merge!(:from => "/#{self.class.collection_name}/#{id}/notes.xml")
5 | Note.find_all_across_pages(options)
6 | end
7 |
8 | def add_note(attrs={})
9 | attrs[:subject_id] = self.id
10 | attrs[:subject_type] = self.label
11 | Note.create attrs
12 | end
13 |
14 | def add_task(attrs={})
15 | attrs[:subject_id] = self.id
16 | attrs[:subject_type] = self.label
17 | Task.create attrs
18 | end
19 |
20 | def emails(options={})
21 | options.merge!(:from => "/#{self.class.collection_name}/#{id}/emails.xml")
22 | Email.find_all_across_pages(options)
23 | end
24 |
25 | def upcoming_tasks(options={})
26 | options.merge!(:from => "/#{self.class.collection_name}/#{id}/tasks.xml")
27 | Task.find(:all, options)
28 | end
29 |
30 | def label
31 | self.class.name.split('::').last
32 | end
33 | end
34 | end
--------------------------------------------------------------------------------
/MIT-LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2010 Ken Mayer & Marcos Tapajos
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining
4 | a copy of this software and associated documentation files (the
5 | "Software"), to deal in the Software without restriction, including
6 | without limitation the rights to use, copy, modify, merge, publish,
7 | distribute, sublicense, and/or sell copies of the Software, and to
8 | permit persons to whom the Software is furnished to do so, subject to
9 | the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be
12 | included in all copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/spec/highrise/kase_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Kase do
4 | it { should be_a_kind_of Highrise::Subject }
5 |
6 | it_should_behave_like "a paginated class"
7 |
8 | it "#close!" do
9 | mocked_now = Time.parse("Wed Jan 14 15:43:11 -0200 2009")
10 | Time.should_receive(:now).and_return(mocked_now)
11 | subject.should_receive(:update_attribute).with(:closed_at, mocked_now.utc)
12 | subject.close!
13 | end
14 |
15 | it "#open!" do
16 | subject.should_receive(:update_attribute).with(:closed_at, nil)
17 | subject.open!
18 | end
19 |
20 | it ".all_open_across_pages" do
21 | subject.class.should_receive(:find).with(:all,{:from=>"/kases/open.xml",:params=>{:n=>0}}).and_return(["things"])
22 | subject.class.should_receive(:find).with(:all,{:from=>"/kases/open.xml",:params=>{:n=>1}}).and_return([])
23 | subject.class.all_open_across_pages.should == ["things"]
24 | end
25 |
26 | it ".all_closed_across_pages" do
27 | subject.class.should_receive(:find).with(:all,{:from=>"/kases/closed.xml",:params=>{:n=>0}}).and_return(["things"])
28 | subject.class.should_receive(:find).with(:all,{:from=>"/kases/closed.xml",:params=>{:n=>1}}).and_return([])
29 | subject.class.all_closed_across_pages.should == ["things"]
30 | end
31 | end
32 |
--------------------------------------------------------------------------------
/highrise.gemspec.erb:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 | require "highrise/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "highrise"
7 | s.version = Highrise::VERSION
8 | s.platform = Gem::Platform::RUBY
9 |
10 | s.required_rubygems_version = ">= 1.3.6"
11 | s.add_dependency "activeresource", ">= 3.2.13"
12 | s.add_development_dependency "rspec"
13 | s.add_development_dependency "rake"
14 |
15 | s.files = <%= `git ls-files`.split("\n") %>
16 | s.test_files = <%= `git ls-files -- {test,spec,features,examples}/*`.split("\n") %>
17 | s.require_paths = ["lib"]
18 |
19 | s.authors = ["Marcos Tapaj\303\263s", "Ken Mayer"]
20 | s.email = ["marcos@tapajos.me", "kmayer@bitwrangler.com"]
21 | s.homepage = "http://github.com/tapajos/highrise"
22 | s.summary = "Ruby wrapper around Highrise API"
23 | s.description = <<-EOT
24 | Based on the original API module from DHH, http://developer.37signals.com/highrise/, this
25 | gem is a cleaned up, tested version of the same.
26 |
27 | Configure by adding the following:
28 |
29 | require 'highrise'
30 | Highrise::Base.site = 'http://your_site.highrisehq.com/'
31 | Highrise::Base.user = 'your_api_auth_token'
32 | EOT
33 |
34 | end
--------------------------------------------------------------------------------
/certs/gem-public_cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
2 | MIIDbDCCAlSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA+MRAwDgYDVQQDDAd0YXBh
3 | am9zMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
4 | HhcNMTMwMzA1MDEyMjQ3WhcNMTQwMzA1MDEyMjQ3WjA+MRAwDgYDVQQDDAd0YXBh
5 | am9zMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZFgNjb20w
6 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDYaGKh+qrV7Ai1jZdQwlHt
7 | /CaUilnHaNHlC5wQh9cniIwjJJ4Ml75m31Yp97Y9piEP+9mND4NqwtF8rYBmDKbJ
8 | J/AiQe1IEeuaZzIA2YCYjEIoBESoJvCDatDHk33nopAHCfYr5vKlx5DVDHWwaoK/
9 | 0+NqHyZ37eRxLOGRg2zAN6tFiWGZuy4ye1mlgZR1PVqLjRT0H9kM3lP31jIPdOaW
10 | IvAGEAA+4SR3SIyAp/8RRWlDsu45TVAhd1gbq9KcqZLYclVWzpqGPDrb9tMiiqKN
11 | he8qj5C04diXGSEbaENnuhhDql7G6QRVaBtD5SSvssSL+g8DEVxQb35vijGm6/NX
12 | AgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQH+XwV
13 | Sqz1jBfSrok4PWfhCQGeXjAcBgNVHREEFTATgRF0YXBham9zQGdtYWlsLmNvbTAc
14 | BgNVHRIEFTATgRF0YXBham9zQGdtYWlsLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEA
15 | qiFtedQQsl7JAU0tQBIj5W3XzyRJxbuR4eq9WOhXBirtLgzZccFphPFSDEatl3Sc
16 | ALC6a86WOmc4Hp023Nb/JamQ2D9nx871k0Cj19tiJDRAbWYEYpim3w+3NXbFzDUE
17 | 0DSKV/BbYqm9vjnj+LnTnCr1qhPPRsPI3xWASv6kRXQ3E3b7NjRSEL+KZ4u0eCjW
18 | qIPM7CDD+hW+YgumNQEED7Qtss2XMiouMysrMNoGUQbJJLBE7I2XwBxKNSA1P2l0
19 | G2tNecqPmHNhgiiojhWB/DTZQKuYJqb+7hCbrLXa/y7kFYwjFR+O0EJvritmuQiS
20 | GVMhotYhO3Lpnij5gFI1AQ==
21 | -----END CERTIFICATE-----
22 |
--------------------------------------------------------------------------------
/spec/highrise/subject_data_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::SubjectData do
4 | it { should be_a_kind_of Highrise::Base }
5 |
6 | it "Two different subject datas with different values are not equal" do
7 | martini = Highrise::SubjectData.new({:id => 1, :value => "Martini", :subject_field_id => 3, :subject_field_label => "Cocktail"})
8 | sling = Highrise::SubjectData.new({:id => 2, :value => "Singapore Sling", :subject_field_id => 4, :subject_field_label => "Cocktail"})
9 | martini.should_not==sling
10 | end
11 |
12 | it "Two different subject datas with different labels are not equal" do
13 | martini = Highrise::SubjectData.new({:id => 1, :value => "Martini", :subject_field_id => 3, :subject_field_label => "Cocktail"})
14 | sling = Highrise::SubjectData.new({:id => 2, :value => "Martini", :subject_field_id => 4, :subject_field_label => "Vermouth Brands"})
15 | martini.should_not==sling
16 | end
17 |
18 | it "Two the same subject datas are equal" do
19 | martini = Highrise::SubjectData.new({:id => 1, :value => "Martini", :subject_field_id => 3, :subject_field_label => "Cocktail"})
20 | another_martini = Highrise::SubjectData.new({:id => 2, :value => "Martini", :subject_field_id => 4, :subject_field_label => "Cocktail"})
21 | martini.should==another_martini
22 | end
23 |
24 | end
--------------------------------------------------------------------------------
/lib/highrise/base.rb:
--------------------------------------------------------------------------------
1 | require 'active_resource'
2 |
3 | module Highrise
4 | class Base < ActiveResource::Base
5 | protected
6 |
7 | class << self
8 | # If headers are not defined in a given subclass, then obtain
9 | # headers from the superclass.
10 | # http://opensoul.org/blog/archives/2010/02/16/active-resource-in-practice/
11 | def headers
12 | if defined?(@headers)
13 | @headers
14 | elsif superclass != Object && superclass.headers
15 | superclass.headers
16 | else
17 | @headers ||= {}
18 | end
19 | end
20 |
21 | def oauth_token=(token)
22 | headers['Authorization'] = "Bearer #{token}"
23 | end
24 | end
25 |
26 | # Fix for ActiveResource 3.1+ errors
27 | self.format = :xml
28 |
29 | # Dynamic finder for attributes
30 | def self.method_missing(method, *args)
31 | if method.to_s =~ /^find_(all_)?by_([_a-zA-Z]\w*)$/
32 | raise ArgumentError, "Dynamic finder method must take an argument." if args.empty?
33 | options = args.extract_options!
34 | resources = respond_to?(:find_all_across_pages) ? send(:find_all_across_pages, options) : send(:find, :all)
35 | resources.send($1 == 'all_' ? 'select' : 'detect') { |container| container.send($2) == args.first }
36 | else
37 | super
38 | end
39 | end
40 |
41 | end
42 | end
43 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | PATH
2 | remote: .
3 | specs:
4 | highrise (3.2.2)
5 | activeresource (>= 3.2.13)
6 |
7 | GEM
8 | remote: https://rubygems.org/
9 | specs:
10 | activemodel (6.0.3.1)
11 | activesupport (= 6.0.3.1)
12 | activemodel-serializers-xml (1.0.2)
13 | activemodel (> 5.x)
14 | activesupport (> 5.x)
15 | builder (~> 3.1)
16 | activeresource (5.1.1)
17 | activemodel (>= 5.0, < 7)
18 | activemodel-serializers-xml (~> 1.0)
19 | activesupport (>= 5.0, < 7)
20 | activesupport (6.0.3.1)
21 | concurrent-ruby (~> 1.0, >= 1.0.2)
22 | i18n (>= 0.7, < 2)
23 | minitest (~> 5.1)
24 | tzinfo (~> 1.1)
25 | zeitwerk (~> 2.2, >= 2.2.2)
26 | builder (3.2.4)
27 | concurrent-ruby (1.1.6)
28 | diff-lcs (1.2.1)
29 | i18n (1.8.2)
30 | concurrent-ruby (~> 1.0)
31 | minitest (5.14.1)
32 | rake (13.0.1)
33 | rspec (2.13.0)
34 | rspec-core (~> 2.13.0)
35 | rspec-expectations (~> 2.13.0)
36 | rspec-mocks (~> 2.13.0)
37 | rspec-core (2.13.0)
38 | rspec-expectations (2.13.0)
39 | diff-lcs (>= 1.1.3, < 2.0)
40 | rspec-mocks (2.13.0)
41 | thread_safe (0.3.6)
42 | thread_safe (0.3.6-java)
43 | tzinfo (1.2.7)
44 | thread_safe (~> 0.1)
45 | zeitwerk (2.3.0)
46 |
47 | PLATFORMS
48 | java
49 | ruby
50 |
51 | DEPENDENCIES
52 | highrise!
53 | rake
54 | rspec
55 |
--------------------------------------------------------------------------------
/spec/highrise/subject_field_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::SubjectField do
4 | it { should be_a_kind_of Highrise::Base }
5 | let(:two_subject_fields){ [
6 | Highrise::SubjectField.new({:id => 1, :label => "Cabbage"}),
7 | Highrise::SubjectField.new({:id => 2, :label => "Chicken"})]
8 | }
9 | let(:four_subject_fields){ [
10 | two_subject_fields,
11 | Highrise::SubjectField.new({:id => 3, :label => "Pasta"}),
12 | Highrise::SubjectField.new({:id => 4, :label => "Beans"})].flatten
13 | }
14 | let(:subject_field_request){ ActiveResource::Request.new(:get, '/subject_fields.xml', nil, {"Authorization"=>"Bearer OAUTH_TOKEN", "Accept"=>"application/xml"}) }
15 | let(:two_subject_fields_request_pair){ {subject_field_request => ActiveResource::Response.new(two_subject_fields.to_xml, 200, {})} }
16 | let(:four_subject_fields_request_pair){ { subject_field_request => ActiveResource::Response.new(four_subject_fields.to_xml, 200, {})} }
17 |
18 | context 'cache disabled (default)' do
19 | it "does not use cache for queries" do
20 | ActiveResource::HttpMock.respond_to(two_subject_fields_request_pair)
21 | Highrise::SubjectField.find(:all)
22 | ActiveResource::HttpMock.respond_to(four_subject_fields_request_pair)
23 | Highrise::SubjectField.find(:all).size.should== 4
24 | end
25 | end
26 |
27 | context 'cache enabled (opt-in)' do
28 | before(:each) do
29 | Highrise::SubjectField.use_cache(true)
30 | end
31 | it "caches 'find all' to prevent too much queries for the SubjectFields" do
32 | ActiveResource::HttpMock.respond_to(two_subject_fields_request_pair)
33 | Highrise::SubjectField.find(:all)
34 | ActiveResource::HttpMock.reset!
35 | Highrise::SubjectField.find(:all).size.should== 2
36 | end
37 | it "invalidates cache" do
38 | ActiveResource::HttpMock.respond_to(two_subject_fields_request_pair)
39 | Highrise::SubjectField.find(:all)
40 | Highrise::SubjectField.invalidate_cache
41 | ActiveResource::HttpMock.respond_to(four_subject_fields_request_pair)
42 | Highrise::SubjectField.find(:all).size.should== 4
43 | end
44 | end
45 |
46 | end
47 |
--------------------------------------------------------------------------------
/spec/highrise/subject_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Subject do
4 | subject { Highrise::Subject.new(:id => 1) }
5 |
6 | it { should be_a_kind_of Highrise::Base }
7 |
8 | it "#notes" do
9 | Highrise::Note.should_receive(:find_all_across_pages).with({:from=>"/subjects/1/notes.xml"}).and_return("notes")
10 | subject.notes.should == "notes"
11 | end
12 |
13 | it "#add_note" do
14 | Highrise::Note.should_receive(:create).with({:body=>"body", :subject_id=>1, :subject_type=>'Subject'}).and_return(mock('note'))
15 | subject.add_note :body=>'body'
16 | end
17 |
18 | it "#add_task" do
19 | Highrise::Task.should_receive(:create).with({:body=>"body", :subject_id=>1, :subject_type=>'Subject'}).and_return(mock('task'))
20 | subject.add_task :body=>'body'
21 | end
22 |
23 | it "#emails" do
24 | Highrise::Email.should_receive(:find_all_across_pages).with({:from=>"/subjects/1/emails.xml"}).and_return("emails")
25 | subject.emails.should == "emails"
26 | end
27 |
28 | it "#upcoming_tasks" do
29 | Highrise::Task.should_receive(:find).with(:all, {:from=>"/subjects/1/tasks.xml"}).and_return("tasks")
30 | subject.upcoming_tasks.should == "tasks"
31 | end
32 |
33 | context 'finding with since param' do
34 | before(:each) do
35 | @utc_time_str = "20090114174311"
36 | end
37 |
38 | it "#notes" do
39 | Highrise::Note.should_receive(:find_all_across_pages).with({:from=>"/subjects/1/notes.xml", :params=>{:since=>@utc_time_str}}).and_return("notes")
40 | subject.notes(:params=>{:since=>@utc_time_str}).should == "notes"
41 | end
42 |
43 | it "#emails" do
44 | Highrise::Email.should_receive(:find_all_across_pages).with({:from=>"/subjects/1/emails.xml", :params=>{:since=>@utc_time_str}}).and_return("emails")
45 | subject.emails(:params=>{:since=>@utc_time_str}).should == "emails"
46 | end
47 |
48 |
49 | it "#tasks" do
50 | Highrise::Task.should_receive(:find).with(:all, {:from=>"/subjects/1/tasks.xml", :params=>{:since=>@utc_time_str}}).and_return("tasks")
51 | subject.upcoming_tasks(:params=>{:since=>@utc_time_str}).should == "tasks"
52 | end
53 | end
54 |
55 | it { subject.label.should == "Subject" }
56 | end
--------------------------------------------------------------------------------
/spec/highrise/base_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Base do
4 | it { subject.should be_a_kind_of ActiveResource::Base }
5 |
6 | describe "dynamic finder methods" do
7 | context "without pagination" do
8 | before do
9 | @deal_one = Highrise::Base.new(:id => 1, :name => "A deal")
10 | @deal_two = Highrise::Base.new(:id => 2, :name => "A deal")
11 | @deal_three = Highrise::Base.new(:id => 3, :name => "Another deal")
12 | Highrise::Base.should_receive(:find).with(:all).and_return([@deal_one, @deal_two, @deal_three])
13 | end
14 | it ".find_by_(attribute) finds one" do
15 | Highrise::Base.find_by_name("A deal").should == @deal_one
16 | end
17 |
18 | it ".find_all_by_(attribute) finds all" do
19 | Highrise::Base.find_all_by_name("A deal").should == [@deal_one, @deal_two]
20 | end
21 | end
22 |
23 | context "with pagination" do
24 | before do
25 | class PaginatedBaseClass < Highrise::Base; include Highrise::Pagination; end
26 | @john_doe = PaginatedBaseClass.new(:id => 1, :first_name => "John")
27 | @john_baker = PaginatedBaseClass.new(:id => 2, :first_name => "John")
28 | @joe_smith = PaginatedBaseClass.new(:id => 3, :first_name => "Joe")
29 | PaginatedBaseClass.should_receive(:find_all_across_pages).and_return([@john_doe, @john_baker, @joe_smith])
30 | end
31 | it ".find_by_(attribute) finds one" do
32 | PaginatedBaseClass.find_by_first_name("John").should == @john_doe
33 | end
34 |
35 | it ".find_all_by_(attribute) finds all" do
36 | PaginatedBaseClass.find_all_by_first_name("John").should == [@john_doe, @john_baker]
37 | end
38 | end
39 |
40 | it "expects arguments to the finder" do
41 | expect { Highrise::Base.find_all_by_first_name }.to raise_error(ArgumentError)
42 | end
43 |
44 | it "falls back to regular method missing" do
45 | expect { Highrise::Base.any_other_method }.to raise_error(NoMethodError)
46 | end
47 | end
48 |
49 | describe "when using an oauth token" do
50 | it ".oauth_token= writes a bearer authorization header" do
51 | Highrise::Base.oauth_token = 'OAUTH_TOKEN'
52 | Highrise::Base.headers['Authorization'].should == 'Bearer OAUTH_TOKEN'
53 | end
54 | end
55 | end
--------------------------------------------------------------------------------
/lib/highrise/custom_fields.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | module CustomFields
3 | def field(field_label)
4 | custom_fields = attributes["subject_datas"] ||= []
5 | field = custom_fields.detect do |field|
6 | field.subject_field_label == field_label
7 | end
8 | field ? field.value : nil
9 | end
10 |
11 | def new_subject_data(field, value)
12 | Highrise::SubjectData.new(:subject_field_id => field.id, :subject_field_label => field.label, :value => value)
13 | end
14 |
15 | def set_field_value(field_label, new_value)
16 | custom_fields = attributes["subject_datas"] ||= []
17 | custom_fields.each do |field|
18 | return field.value = new_value if field.subject_field_label == field_label
19 | end
20 |
21 | SubjectField.find(:all).each do |custom_field|
22 | if custom_field.label == field_label
23 | return attributes["subject_datas"] << new_subject_data(custom_field, new_value)
24 | end
25 | end
26 | end
27 |
28 | def transform_subject_field_label field_label
29 | field_label.downcase.tr(' ', '_')
30 | end
31 |
32 | def convert_method_to_field_label method
33 | custom_fields = attributes["subject_datas"] ||= []
34 | custom_fields.each do |field|
35 | method_name_from_field = transform_subject_field_label(field.subject_field_label)
36 | return field if method_name_from_field == method
37 | end
38 | nil
39 | end
40 |
41 | def method_missing(method_symbol, *args)
42 | method_name = method_symbol.to_s
43 |
44 | if method_name[-1,1] == "="
45 | attribute_name = method_name[0...-1]
46 | field = convert_method_to_field_label(attribute_name)
47 | return set_field_value(field.subject_field_label, args[0]) if field
48 |
49 | return super if attributes[attribute_name]
50 |
51 | subject_fields = SubjectField.find(:all)
52 | unless subject_fields.nil?
53 | subject_fields.each do |custom_field|
54 | if transform_subject_field_label(custom_field.label) == attribute_name
55 | return attributes["subject_datas"] << new_subject_data(custom_field, args[0])
56 | end
57 | end
58 | end
59 | else
60 | field = convert_method_to_field_label(method_name)
61 | return field(field.subject_field_label) if field
62 | end
63 | super
64 | end
65 | end
66 | end
67 |
--------------------------------------------------------------------------------
/lib/highrise/pagination.rb:
--------------------------------------------------------------------------------
1 | module Highrise
2 | module Pagination
3 | def self.included(base)
4 | base.extend(ClassMethods)
5 | end
6 |
7 | module ClassMethods
8 | def find_all_across_pages(options = {})
9 | records = []
10 | each(options) { |record| records << record }
11 | records
12 | end
13 |
14 | # This only is usefull for company, person & recordings, but should be safely ignored by other classes
15 | def find_all_across_pages_since(time)
16 | find_all_across_pages(:params => { :since => time.utc.strftime("%Y%m%d%H%M%S") })
17 | end
18 |
19 | # This is useful only for Company, Person, Note, Comment, Email and Task, but should be safely ignored by other classes
20 | def find_all_deletions_across_pages(options = {})
21 | # point to the global deletions feed
22 | options[:from] = '/deletions.xml'
23 |
24 | records = []
25 | each_deletions(options) { |record| records << record }
26 | records
27 | end
28 |
29 | # This is useful only for Company, Person, Note, Comment, Email and Task, but should be safely ignored by other classes
30 | def find_all_deletions_across_pages_since(time)
31 | find_all_deletions_across_pages(:params => { :since => time.utc.strftime("%Y%m%d%H%M%S") })
32 | end
33 |
34 | private
35 |
36 | def each(options = {})
37 | options[:params] ||= {}
38 | options[:params][:n] = 0
39 |
40 | loop do
41 | if (records = self.find(:all, options)).try(:any?)
42 | records.each { |record| yield record }
43 | options[:params][:n] += records.size
44 | else
45 | break # no people included on that page, thus no more people total
46 | end
47 | end
48 | end
49 |
50 | def each_deletions(options = {})
51 | options[:params] ||= {}
52 | # first index for deletions is 1
53 | options[:params][:n] = 1
54 |
55 | loop do
56 | if (records = self.find(:all, options)).try(:any?)
57 | # reject the records whose resource type is different from self
58 | records.reject!{|r| r.class.to_s.split('::').last != self.to_s.split('::').last}
59 |
60 | records.each{ |record| yield record }
61 |
62 | # index increment for deletions is 1 per page of 500 resources
63 | options[:params][:n] += 1
64 | else
65 | break # no deletions included on that page, thus no more deletions
66 | end
67 | end
68 | end
69 |
70 | end
71 | end
72 | end
73 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Highrise (master) [](https://snap-ci.com/tapajos/highrise/branch/master) [](https://codeclimate.com/github/tapajos/highrise)
2 |
3 | ## What is it?
4 |
5 | This gem provides a set of classes to access information on [Highrise][h] via the published [API][api]:
6 |
7 | Account, Comment, Company, Deal, DealCategory, Email, Group, Case, Membership,
8 | Note, Party, Person, Recording, Subject, Tag, Task, TaskCategory and User.
9 |
10 | All these classes are inherited from ActiveResouce::Base. Refer to the [ActiveResouce][ar] documentation for more information.
11 |
12 | ## Installing
13 | ```bash
14 | gem install highrise
15 | ```
16 | ### Dependencies (see highrise.gemspec or run bundle check)
17 |
18 | ### Documentation
19 |
20 | I'm on [rdoc.info][rdoc] (or am I?)
21 |
22 | [Cookbook][cookbook]
23 |
24 | ### Configure your key
25 | ```ruby
26 | require 'highrise'
27 |
28 | Highrise::Base.site = 'https://your_site.highrisehq.com'
29 | Highrise::Base.user = 'api-auth-token'
30 | Highrise::Base.format = :xml
31 | ```
32 |
33 | If you are using this in a Rails application, putting this code in a config/initializers/highrise.rb
34 | file is recommended. See config_initializers_highrise.rb in the examples/ directory.
35 |
36 | ## Usage
37 | ```ruby
38 | @tags = Highrise::Tag.find(:all)
39 |
40 | @people = Highrise::Person.find_all_across_pages(:params => {:tag_id => 12345})
41 |
42 | @person.tag!("VIP")
43 | ```
44 | ## License
45 |
46 | This code is free to be used under the terms of the [MIT license][mit].
47 |
48 | ## Bugs, Issues, Kudos and Catcalls
49 |
50 | Comments are welcome. Send your feedback through the [issue tracker on GitHub][i]
51 |
52 | If you have fixes: Submit via pull requests. Do not include version changes to the
53 | version file.
54 |
55 | ## Authors
56 |
57 | * [Marcos Tapajós][tapajos]
58 | * [Ken Mayer][kmayer]
59 |
60 | ## [Contributors][list]
61 |
62 |
63 | [api]: http://developer.37signals.com/highrise
64 | [ar]: http://api.rubyonrails.org/classes/ActiveResource/Base.html
65 | [c]: http://api.rubyonrails.org/classes/ActiveSupport/Cache
66 | [h]: http://www.highrisehq.com/
67 | [i]: https://github.com/tapajos/highrise/issues
68 | [kmayer]: https://github.com/kmayer
69 | [mit]: http://www.opensource.org/licenses/mit-license.php
70 | [cookbook]: https://github.com/tapajos/highrise/wiki/Cookbook
71 | [rdoc]: http://rdoc.info/projects/tapajos/highrise
72 | [tapajos]: http://www.improveit.com.br/en/company/tapajos
73 | [list]: https://github.com/tapajos/highrise/graphs/contributors
74 | []
75 |
--------------------------------------------------------------------------------
/spec/highrise/pagination_behavior.rb:
--------------------------------------------------------------------------------
1 | shared_examples_for "a paginated class" do
2 | it { subject.class.included_modules.should include(Highrise::Pagination) }
3 |
4 | it ".find_all_across_pages" do
5 | subject.class.should_receive(:find).with(:all,{:params=>{:n=>0}}).and_return(["things"])
6 | subject.class.should_receive(:find).with(:all,{:params=>{:n=>1}}).and_return([])
7 | subject.class.find_all_across_pages.should == ["things"]
8 | end
9 |
10 | it ".find_all_across_pages with zero results" do
11 | subject.class.should_receive(:find).with(:all,{:params=>{:n=>0}}).and_return(nil)
12 | subject.class.find_all_across_pages.should == []
13 | end
14 |
15 | it ".find_all_across_pages_since" do
16 | time = Time.parse("Wed Jan 14 15:43:11 -0200 2009")
17 | subject.class.should_receive(:find_all_across_pages).with({:params=>{:since=>"20090114174311"}}).and_return("result")
18 | subject.class.find_all_across_pages_since(time).should == "result"
19 | end
20 |
21 | it ".find_all_deletions_across_pages" do
22 | class TestClass2 < Highrise::Base; include Highrise::Pagination; end
23 | subject_type = subject.class.to_s.split('::').last
24 | deleted_resource_1 = subject.class.new(:id => 12, :type => subject_type)
25 | deleted_resource_2 = TestClass2.new(:id => 34, :type => 'TestClass2')
26 | deleted_resource_3 = subject.class.new(:id => 45, :type => subject_type)
27 |
28 | subject.class.should_receive(:find).with(:all,{:from => '/deletions.xml', :params=>{:n=>1}}).and_return([deleted_resource_1, deleted_resource_2, deleted_resource_3])
29 | subject.class.should_receive(:find).with(:all,{:from => '/deletions.xml', :params=>{:n=>2}}).and_return([])
30 | subject.class.find_all_deletions_across_pages.should == [deleted_resource_1, deleted_resource_3]
31 | end
32 |
33 | it ".find_all_deletions_across_pages with zero results" do
34 | subject.class.should_receive(:find).with(:all,{:from => '/deletions.xml', :params=>{:n=>1}}).and_return(nil)
35 | subject.class.find_all_deletions_across_pages.should == []
36 | end
37 |
38 | it ".find_all_deletions_across_pages_since" do
39 | class TestClass2 < Highrise::Base; include Highrise::Pagination; end
40 | subject_type = subject.class.to_s.split('::').last
41 | time = Time.parse("Wed Jan 14 15:43:11 -0200 2009")
42 | deleted_resource_1 = subject.class.new(:id => 12, :type => subject_type)
43 | deleted_resource_2 = TestClass2.new(:id => 34, :type => 'TestClass2')
44 | deleted_resource_3 = subject.class.new(:id => 45, :type => subject_type)
45 |
46 | subject.class.should_receive(:find).with(:all,{:from => '/deletions.xml', :params=>{:n=>1, :since=>"20090114174311"}}).and_return([deleted_resource_1, deleted_resource_2, deleted_resource_3])
47 | subject.class.should_receive(:find).with(:all,{:from => '/deletions.xml', :params=>{:n=>2, :since=>"20090114174311"}}).and_return([])
48 | subject.class.find_all_deletions_across_pages_since(time).should == [deleted_resource_1, deleted_resource_3]
49 | end
50 | end
51 |
--------------------------------------------------------------------------------
/spec/highrise/company_spec.rb:
--------------------------------------------------------------------------------
1 | require 'spec_helper'
2 |
3 | describe Highrise::Company do
4 | subject { Highrise::Company.new(:id => 1) }
5 |
6 | it { should be_a_kind_of Highrise::Base }
7 | it_should_behave_like "a paginated class"
8 | it_should_behave_like "a taggable class"
9 | it_should_behave_like "a searchable class"
10 |
11 | it "#people" do
12 | Highrise::Person.should_receive(:find_all_across_pages).with(:from=>"/companies/1/people.xml").and_return("people")
13 | subject.people.should == "people"
14 | end
15 |
16 | describe "Custom fields" do
17 |
18 | before (:each) do
19 | @fruit_company = Highrise::Company.new({ :company => {
20 | :id => 1,
21 | :name => "John Doe & Co.",
22 | :subject_datas => [{
23 | :subject_field_label => "Fruit Banana",
24 | :value => "Yellow"
25 | }, {
26 | :subject_field_label => "Fruit Grape",
27 | :value => "Green"
28 | }]
29 | }
30 | })
31 | @subject_field_blueberry = Highrise::SubjectField.new ({:id => 1, :label => "Fruit Blueberry"})
32 | @subject_field_papaya = Highrise::SubjectField.new ({:id => 2, :label => "Fruit Papaya"})
33 | end
34 |
35 | it "Can get the value of a custom field via the field method" do
36 | @fruit_company.field("Fruit Banana").should== "Yellow"
37 | end
38 |
39 | it "Can get the value of a custom field using a custom method call" do
40 | @fruit_company.fruit_grape.should== "Green"
41 | end
42 |
43 | it "Will raise an exception on an unknown field" do
44 | expect {@fruit_company.unknown_fruit}.to raise_exception(NoMethodError)
45 | end
46 |
47 | it "Can set the value of a custom field via the field method" do
48 | @fruit_company.set_field_value("Fruit Grape", "Red")
49 | @fruit_company.field("Fruit Grape").should== "Red"
50 | end
51 |
52 | it "Can set the value of a custom field" do
53 | @fruit_company.fruit_grape= "Red"
54 | @fruit_company.field("Fruit Grape").should== "Red"
55 | end
56 |
57 | it "Assignment just returns the arguments (like ActiveResource base does)" do
58 | Highrise::SubjectField.should_receive(:find).with(:all).and_return []
59 | (@fruit_company.unknown_fruit = 10).should== 10
60 | end
61 |
62 | it "Can deal with the find returning nil (which is a bit ugly in the ActiveResource API)" do
63 | Highrise::SubjectField.should_receive(:find).with(:all).and_return nil
64 | (@fruit_company.unknown_fruit = 10).should== 10
65 | end
66 |
67 | it "Can set the value of a custom field that wasn't there via the field method, but that was defined (happens on new Person)" do
68 | Highrise::SubjectField.should_receive(:find).with(:all).and_return([@subject_field_papaya, @subject_field_blueberry])
69 | @fruit_company.set_field_value("Fruit Blueberry", "Purple")
70 | @fruit_company.field("Fruit Blueberry").should== "Purple"
71 | @fruit_company.attributes["subject_datas"][2].subject_field_id.should == 1
72 | end
73 |
74 | it "Can still set and read the usual way of reading attrivutes" do
75 | @fruit_company.name = "Jacob"
76 | @fruit_company.name.should== "Jacob"
77 |
78 | end
79 |
80 | end
81 |
82 | it { subject.label.should == 'Party' }
83 | end
84 |
--------------------------------------------------------------------------------
/highrise.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | $:.push File.expand_path("../lib", __FILE__)
3 | require "highrise/version"
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "highrise"
7 | s.version = Highrise::VERSION
8 | s.platform = Gem::Platform::RUBY
9 |
10 | s.required_rubygems_version = ">= 1.3.6"
11 | s.add_dependency "activeresource", ">= 3.2.13"
12 | s.add_development_dependency "rspec"
13 | s.add_development_dependency "rake"
14 |
15 | s.files = [".gitignore", ".ruby-version", ".travis.yml", "Gemfile", "Gemfile.lock", "MIT-LICENSE", "README.md", "Rakefile", "autotest/discover.rb", "certs/gem-public_cert.pem", "examples/config_initializers_highrise.rb", "examples/extending.rb", "examples/sample.rb", "highrise.gemspec", "highrise.gemspec.erb", "lib/highrise.rb", "lib/highrise/account.rb", "lib/highrise/base.rb", "lib/highrise/comment.rb", "lib/highrise/company.rb", "lib/highrise/custom_fields.rb", "lib/highrise/deal.rb", "lib/highrise/deal_category.rb", "lib/highrise/email.rb", "lib/highrise/group.rb", "lib/highrise/kase.rb", "lib/highrise/membership.rb", "lib/highrise/note.rb", "lib/highrise/pagination.rb", "lib/highrise/party.rb", "lib/highrise/person.rb", "lib/highrise/recording.rb", "lib/highrise/searchable.rb", "lib/highrise/subject.rb", "lib/highrise/subject_data.rb", "lib/highrise/subject_field.rb", "lib/highrise/tag.rb", "lib/highrise/taggable.rb", "lib/highrise/task.rb", "lib/highrise/task_category.rb", "lib/highrise/user.rb", "lib/highrise/version.rb", "spec/highrise/account_spec.rb", "spec/highrise/base_spec.rb", "spec/highrise/comment_spec.rb", "spec/highrise/company_spec.rb", "spec/highrise/deal_category_spec.rb", "spec/highrise/deal_spec.rb", "spec/highrise/email_spec.rb", "spec/highrise/group_spec.rb", "spec/highrise/kase_spec.rb", "spec/highrise/membership_spec.rb", "spec/highrise/note_spec.rb", "spec/highrise/pagination_behavior.rb", "spec/highrise/pagination_spec.rb", "spec/highrise/party_spec.rb", "spec/highrise/person_spec.rb", "spec/highrise/recording_spec.rb", "spec/highrise/searchable_behavior.rb", "spec/highrise/searchable_spec.rb", "spec/highrise/subject_data_spec.rb", "spec/highrise/subject_field_spec.rb", "spec/highrise/subject_spec.rb", "spec/highrise/tag_spec.rb", "spec/highrise/taggable_behavior.rb", "spec/highrise/taggable_spec.rb", "spec/highrise/task_category_spec.rb", "spec/highrise/task_spec.rb", "spec/highrise/user_spec.rb", "spec/spec_helper.rb"]
16 | s.test_files = ["examples/config_initializers_highrise.rb", "examples/extending.rb", "examples/sample.rb", "spec/highrise/account_spec.rb", "spec/highrise/base_spec.rb", "spec/highrise/comment_spec.rb", "spec/highrise/company_spec.rb", "spec/highrise/deal_category_spec.rb", "spec/highrise/deal_spec.rb", "spec/highrise/email_spec.rb", "spec/highrise/group_spec.rb", "spec/highrise/kase_spec.rb", "spec/highrise/membership_spec.rb", "spec/highrise/note_spec.rb", "spec/highrise/pagination_behavior.rb", "spec/highrise/pagination_spec.rb", "spec/highrise/party_spec.rb", "spec/highrise/person_spec.rb", "spec/highrise/recording_spec.rb", "spec/highrise/searchable_behavior.rb", "spec/highrise/searchable_spec.rb", "spec/highrise/subject_data_spec.rb", "spec/highrise/subject_field_spec.rb", "spec/highrise/subject_spec.rb", "spec/highrise/tag_spec.rb", "spec/highrise/taggable_behavior.rb", "spec/highrise/taggable_spec.rb", "spec/highrise/task_category_spec.rb", "spec/highrise/task_spec.rb", "spec/highrise/user_spec.rb", "spec/spec_helper.rb"]
17 | s.require_paths = ["lib"]
18 |
19 | s.authors = ["Marcos Tapaj\303\263s", "Ken Mayer"]
20 | s.email = ["marcos@tapajos.me", "kmayer@bitwrangler.com"]
21 | s.homepage = "http://github.com/tapajos/highrise"
22 | s.summary = "Ruby wrapper around Highrise API"
23 | s.description = <<-EOT
24 | Based on the original API module from DHH, http://developer.37signals.com/highrise/, this
25 | gem is a cleaned up, tested version of the same.
26 |
27 | Configure by adding the following:
28 |
29 | require 'highrise'
30 | Highrise::Base.site = 'http://your_site.highrisehq.com/'
31 | Highrise::Base.user = 'your_api_auth_token'
32 | EOT
33 |
34 | end
--------------------------------------------------------------------------------
/spec/highrise/person_spec.rb:
--------------------------------------------------------------------------------
1 | # encoding: utf-8
2 | require 'spec_helper'
3 |
4 | describe Highrise::Person do
5 | subject { Highrise::Person.new(:id => 1) }
6 |
7 | it { should be_a_kind_of Highrise::Subject }
8 |
9 | it_should_behave_like "a paginated class"
10 | it_should_behave_like "a taggable class"
11 | it_should_behave_like "a searchable class"
12 |
13 | describe "#company" do
14 | it "returns nil when it doesn't have a company" do
15 | subject.should_receive(:company_id).and_return(nil)
16 | subject.company.should be_nil
17 | end
18 |
19 | it "delegate to Highrise::Company when have company_id" do
20 | subject.should_receive(:company_id).at_least(2).times.and_return(1)
21 | Highrise::Company.should_receive(:find).with(1).and_return("company")
22 | subject.company.should == "company"
23 | end
24 | end
25 |
26 | it "#name" do
27 | subject.should_receive(:first_name).and_return("Marcos")
28 | subject.should_receive(:last_name).and_return("Tapajós ")
29 | subject.name.should == "Marcos Tapajós"
30 | end
31 |
32 | describe "#email_addresses" do
33 | it "returns an empty array when there are none set" do
34 | subject.email_addresses.should == []
35 | end
36 |
37 | it "returns all email_addresses as string in an array" do
38 | subject = Highrise::Person.new(:id => 1,
39 | :contact_data => {
40 | :email_addresses => [{
41 | :email_address => {
42 | :address => "important@person.com"
43 | }
44 | }]
45 | })
46 | subject.email_addresses.should == ["important@person.com"]
47 | end
48 | end
49 |
50 | describe "#phone_numbers" do
51 | it "returns an empty array when there is none set" do
52 | subject.phone_numbers.should== []
53 | end
54 |
55 | it "returns all phone numbers as a string aray" do
56 | subject = Highrise::Person.new(:id => 1,
57 | :contact_data => {
58 | :phone_numbers => [{
59 | :phone_number => {
60 | :number => "123456789"
61 | }
62 | }]
63 | })
64 | subject.phone_numbers.should== [ "123456789" ]
65 | end
66 | end
67 |
68 | describe "#tags" do
69 |
70 | let(:person_tags) { [
71 | {'id' => "414578", 'name' => "cliente"},
72 | {'id' => "414580", 'name' => "ged"},
73 | {'id' => "414579", 'name' => "iepc"} ]
74 | }
75 |
76 | let(:person_john_doe) { { :id => 1, :first_name => "John", :last_name => "Doe" } }
77 | let(:person_john_doe_request){ ActiveResource::Request.new(:get, '/people/1.xml', nil, {"Authorization"=>"Bearer OAUTH_TOKEN", "Accept"=>"application/xml"}) }
78 | let(:person_john_doe_request_pair){ {person_john_doe_request => ActiveResource::Response.new(person_john_doe.to_xml, 200, {})} }
79 |
80 | it "should return the tags as a Highrise::Tag" do
81 | person_john_doe[:tags] = person_tags
82 | ActiveResource::HttpMock.respond_to(person_john_doe_request_pair)
83 | tags = person_tags.collect {|tag| Highrise::Tag.new(tag)}
84 | subject.tags.should == tags
85 | end
86 |
87 | it "should return an empty collection when there are no tags" do
88 | ActiveResource::HttpMock.respond_to(person_john_doe_request_pair)
89 | subject.tags.should == []
90 | end
91 | end
92 |
93 |
94 | describe "#tags" do
95 | before(:each) do
96 | (@tags = []).tap do
97 | @tags << {'id' => "414578", 'name' => "cliente"}
98 | @tags << {'id' => "414580", 'name' => "ged"}
99 | @tags << {'id' => "414579", 'name' => "iepc"}
100 | end
101 | subject.attributes["tags"] = @tags
102 | end
103 | it {
104 | subject.tags.should == @tags
105 | }
106 | end
107 |
108 | describe "Custom fields" do
109 |
110 | before (:each) do
111 | @fruit_person = Highrise::Person.new({ :person => {
112 | :id => 1,
113 | :first_name => "John",
114 | :last_name => "Doe",
115 | :subject_datas => [{
116 | :subject_field_label => "Fruit Banana",
117 | :value => "Yellow"
118 | }, {
119 | :subject_field_label => "Fruit Grape",
120 | :value => "Green"
121 | }]
122 | }
123 | })
124 | @subject_field_blueberry = Highrise::SubjectField.new ({:id => 1, :label => "Fruit Blueberry"})
125 | @subject_field_papaya = Highrise::SubjectField.new ({:id => 2, :label => "Fruit Papaya"})
126 | end
127 |
128 | it "Can get the value of a custom field via the field method" do
129 | @fruit_person.field("Fruit Banana").should== "Yellow"
130 | end
131 |
132 | it "Can get the value of a custom field using a custom method call" do
133 | @fruit_person.fruit_grape.should== "Green"
134 | end
135 |
136 | it "Will raise an exception on an unknown field" do
137 | expect {@fruit_person.unknown_fruit}.to raise_exception(NoMethodError)
138 | end
139 |
140 | it "Can set the value of a custom field via the field method" do
141 | @fruit_person.set_field_value("Fruit Grape", "Red")
142 | @fruit_person.field("Fruit Grape").should== "Red"
143 | end
144 |
145 | it "Can set the value of a custom field" do
146 | @fruit_person.fruit_grape= "Red"
147 | @fruit_person.fruit_grape.should== "Red"
148 | end
149 |
150 | it "Assignment just returns the arguments (like ActiveResource base does)" do
151 | Highrise::SubjectField.should_receive(:find).with(:all).and_return []
152 | (@fruit_person.unknown_fruit = 10).should== 10
153 | end
154 |
155 | it "Can deal with the find returning nil (which is a bit ugly in the ActiveResource API)" do
156 | Highrise::SubjectField.should_receive(:find).with(:all).and_return nil
157 | (@fruit_person.unknown_fruit = 10).should== 10
158 | end
159 |
160 | it "Can set the value of a custom field that wasn't there via the field method, but that was defined (happens on new Person)" do
161 | Highrise::SubjectField.should_receive(:find).with(:all).and_return([@subject_field_papaya, @subject_field_blueberry])
162 | @fruit_person.set_field_value("Fruit Blueberry", "Purple")
163 | @fruit_person.field("Fruit Blueberry").should== "Purple"
164 | @fruit_person.attributes["subject_datas"][2].subject_field_id.should == 1
165 | end
166 |
167 | it "Can still set and read the usual way of reading attrivutes" do
168 | @fruit_person.first_name = "Jacob"
169 | @fruit_person.first_name.should== "Jacob"
170 |
171 | end
172 |
173 | end
174 |
175 | it { subject.label.should == 'Party' }
176 | end
177 |
--------------------------------------------------------------------------------