crowdflower 0.4.5 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.md +9 -0
- data/VERSION +1 -1
- data/crowdflower.gemspec +23 -25
- data/lib/crowdflower.rb +1 -1
- data/lib/crowdflower/base.rb +155 -30
- data/lib/crowdflower/job.rb +35 -42
- data/lib/crowdflower/judgment.rb +27 -8
- data/lib/crowdflower/order.rb +4 -4
- data/lib/crowdflower/unit.rb +11 -11
- data/lib/crowdflower/worker.rb +54 -0
- data/test/integration_tests.rb +36 -1
- metadata +9 -9
- data/.gitignore +0 -8
    
        data/HISTORY.md
    CHANGED
    
    | @@ -1,3 +1,12 @@ | |
| 1 | 
            +
            ## 0.5.1 (2011-02-03)
         | 
| 2 | 
            +
            * Added individual judgment rejection to API.
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            ## 0.5.0 (2011-02-01)
         | 
| 5 | 
            +
            * Worker API added for managing workers (flagging, approving, etc.)
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## 0.4.6 (2010-12-17)
         | 
| 8 | 
            +
            * Multiple API keys can be used simultaneously
         | 
| 9 | 
            +
             | 
| 1 10 | 
             
            ## 0.4.0 (2010-03-25)
         | 
| 2 11 | 
             
            * Allow key configuration from YAML
         | 
| 3 12 | 
             
            * ruby-crowdflower is now just 'crowdflower'
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.5.2
         | 
    
        data/crowdflower.gemspec
    CHANGED
    
    | @@ -1,15 +1,15 @@ | |
| 1 1 | 
             
            # Generated by jeweler
         | 
| 2 2 | 
             
            # DO NOT EDIT THIS FILE DIRECTLY
         | 
| 3 | 
            -
            # Instead, edit Jeweler::Tasks in Rakefile, and run  | 
| 3 | 
            +
            # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
         | 
| 4 4 | 
             
            # -*- encoding: utf-8 -*-
         | 
| 5 5 |  | 
| 6 6 | 
             
            Gem::Specification.new do |s|
         | 
| 7 7 | 
             
              s.name = %q{crowdflower}
         | 
| 8 | 
            -
              s.version = "0. | 
| 8 | 
            +
              s.version = "0.5.3"
         | 
| 9 9 |  | 
| 10 10 | 
             
              s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
         | 
| 11 11 | 
             
              s.authors = ["Brian P O'Rourke", "Chris Van Pelt"]
         | 
| 12 | 
            -
              s.date = %q{ | 
| 12 | 
            +
              s.date = %q{2011-02-10}
         | 
| 13 13 | 
             
              s.description = %q{A toolkit for interacting with CrowdFlower via the REST API.
         | 
| 14 14 |  | 
| 15 15 | 
             
            This is alpha software. Have fun!
         | 
| @@ -18,40 +18,38 @@ This is alpha software. Have fun! | |
| 18 18 | 
             
              s.email = %q{brian@doloreslabs.com}
         | 
| 19 19 | 
             
              s.extra_rdoc_files = [
         | 
| 20 20 | 
             
                "LICENSE",
         | 
| 21 | 
            -
             | 
| 21 | 
            +
                "README.md"
         | 
| 22 22 | 
             
              ]
         | 
| 23 23 | 
             
              s.files = [
         | 
| 24 24 | 
             
                ".document",
         | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 25 | 
            +
                "CONTRIBUTORS",
         | 
| 26 | 
            +
                "HISTORY.md",
         | 
| 27 | 
            +
                "LICENSE",
         | 
| 28 | 
            +
                "README.md",
         | 
| 29 | 
            +
                "Rakefile",
         | 
| 30 | 
            +
                "VERSION",
         | 
| 31 | 
            +
                "bindev/cl_skel.rb",
         | 
| 32 | 
            +
                "bindev/crowdflower.rb",
         | 
| 33 | 
            +
                "crowdflower.gemspec",
         | 
| 34 | 
            +
                "lib/crowdflower.rb",
         | 
| 35 | 
            +
                "lib/crowdflower/base.rb",
         | 
| 36 | 
            +
                "lib/crowdflower/job.rb",
         | 
| 37 | 
            +
                "lib/crowdflower/judgment.rb",
         | 
| 38 | 
            +
                "lib/crowdflower/order.rb",
         | 
| 39 | 
            +
                "lib/crowdflower/unit.rb",
         | 
| 40 | 
            +
                "lib/crowdflower/worker.rb",
         | 
| 41 | 
            +
                "test/integration_tests.rb",
         | 
| 42 | 
            +
                "test/sample.csv"
         | 
| 43 43 | 
             
              ]
         | 
| 44 44 | 
             
              s.homepage = %q{http://github.com/dolores/ruby-crowdflower}
         | 
| 45 | 
            -
              s.rdoc_options = ["--charset=UTF-8"]
         | 
| 46 45 | 
             
              s.require_paths = ["lib"]
         | 
| 47 | 
            -
              s.rubygems_version = %q{1. | 
| 46 | 
            +
              s.rubygems_version = %q{1.5.0}
         | 
| 48 47 | 
             
              s.summary = %q{a toolkit for the CrowdFlower API}
         | 
| 49 48 | 
             
              s.test_files = [
         | 
| 50 49 | 
             
                "test/integration_tests.rb"
         | 
| 51 50 | 
             
              ]
         | 
| 52 51 |  | 
| 53 52 | 
             
              if s.respond_to? :specification_version then
         | 
| 54 | 
            -
                current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
         | 
| 55 53 | 
             
                s.specification_version = 3
         | 
| 56 54 |  | 
| 57 55 | 
             
                if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
         | 
    
        data/lib/crowdflower.rb
    CHANGED
    
    
    
        data/lib/crowdflower/base.rb
    CHANGED
    
    | @@ -13,42 +13,167 @@ module CrowdFlower | |
| 13 13 | 
             
                end
         | 
| 14 14 | 
             
              end
         | 
| 15 15 |  | 
| 16 | 
            -
               | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
                 | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 16 | 
            +
              # a convenience method for backward compatibility
         | 
| 17 | 
            +
              def self.connect!(key, development = false, version = 1)
         | 
| 18 | 
            +
                Base.connect!(key, development, version)
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              def self.connect_domain!(key, domain_base, version = 1)
         | 
| 22 | 
            +
                Base.connect_domain!(key, domain_base, version)
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
              def self.connect_config!(opts)
         | 
| 26 | 
            +
                Base.connect_config!(opts)
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              
         | 
| 29 | 
            +
              # an object that stores connection details; does actual http talking
         | 
| 30 | 
            +
              class Connection
         | 
| 31 | 
            +
                include HTTParty
         | 
| 32 | 
            +
                headers "accept" => "application/json"
         | 
| 33 | 
            +
                format :json
         | 
| 34 | 
            +
                
         | 
| 35 | 
            +
                attr_reader :key, :domain, :version, :domain_base, :ssl_port, :public_port
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                def initialize(key, domain_base, version, ssl_port = 443, public_port = 80)
         | 
| 38 | 
            +
                  @domain_base = domain_base
         | 
| 39 | 
            +
                  @version = version
         | 
| 40 | 
            +
                  @domain = "#{@domain_base}/v#{version}"
         | 
| 41 | 
            +
                  @key = key
         | 
| 42 | 
            +
                  @ssl_port = ssl_port
         | 
| 43 | 
            +
                  @public_port = public_port
         | 
| 44 | 
            +
                  begin # pass yaml file
         | 
| 45 | 
            +
                    key = YAML.load_file(key)
         | 
| 46 | 
            +
                    @key = key[:key] || key["key"]
         | 
| 47 | 
            +
                  rescue # pass key
         | 
| 48 | 
            +
                    @key = key
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                # get, post, put and delete methods
         | 
| 53 | 
            +
                def method_missing(method_id, *args)
         | 
| 54 | 
            +
                  if [:get, :post, :put, :delete].include?(method_id)
         | 
| 55 | 
            +
                    path, options = *args
         | 
| 56 | 
            +
                    options ||= {}
         | 
| 57 | 
            +
                    options[:body] = default_params.merge(options[:body] || {})
         | 
| 58 | 
            +
                    options[:query] = (default_params.merge(options[:query] || {}))
         | 
| 59 | 
            +
                    options[:headers] = (self.class.default_options[:headers].merge(options[:headers] || {}))
         | 
| 60 | 
            +
                    
         | 
| 61 | 
            +
                    self.class.send(method_id, url(path), options)
         | 
| 62 | 
            +
                  else
         | 
| 63 | 
            +
                    super
         | 
| 31 64 | 
             
                  end
         | 
| 32 65 | 
             
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                # Returns the base crowdflower domain from the api url's domain.
         | 
| 68 | 
            +
                #
         | 
| 69 | 
            +
                # @api public
         | 
| 70 | 
            +
                # @return [String] the base crowdflower domain
         | 
| 71 | 
            +
                # @example
         | 
| 72 | 
            +
                #   CrowdFlower::Connection.new("asdf", "https://api.crowdflower.com").crowdflower_base #=> "crowdflower.com"
         | 
| 73 | 
            +
                def crowdflower_base
         | 
| 74 | 
            +
                  uri = URI.parse(domain_base)
         | 
| 75 | 
            +
                  "#{uri.host.gsub("api.", "")}"
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                # Returns the url to reach crowdflower regularly through a browser
         | 
| 79 | 
            +
                #
         | 
| 80 | 
            +
                # @api public
         | 
| 81 | 
            +
                # @return [String] the url to reach crowdflower in a browser
         | 
| 82 | 
            +
                # @example
         | 
| 83 | 
            +
                #   CrowdFlower::Connection.new("asdf", "https://api.crowdflower.com").public_url #=> "crowdflower.com:80"
         | 
| 84 | 
            +
                def public_url
         | 
| 85 | 
            +
                  "#{crowdflower_base}:#{public_port}"
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                private
         | 
| 89 | 
            +
                def url(path)
         | 
| 90 | 
            +
                  "#{@domain}/#{path}"
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
                
         | 
| 93 | 
            +
                def default_params
         | 
| 94 | 
            +
                  {'key' => @key}
         | 
| 95 | 
            +
                end
         | 
| 33 96 | 
             
              end
         | 
| 34 97 |  | 
| 35 | 
            -
               | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
             | 
| 42 | 
            -
             | 
| 43 | 
            -
             | 
| 98 | 
            +
              
         | 
| 99 | 
            +
              # Base class for Crowdflower api entities.
         | 
| 100 | 
            +
              # Now instead of one global configuration, each instance could maintain its own connection.
         | 
| 101 | 
            +
              # If no connection is available for an instance it will look for default class-level or global
         | 
| 102 | 
            +
              # connection settings, see Base#connection method.
         | 
| 103 | 
            +
              # You can set class-specific connection with Base.connect! call
         | 
| 104 | 
            +
              # for example:
         | 
| 105 | 
            +
              #     Job.connect!(api_key, development, version).
         | 
| 106 | 
            +
              # It is possible to use several api keys simultaneously either by providing each entity instance
         | 
| 107 | 
            +
              # with a specific Connection object or by creating entity subclasses that have their own default connections
         | 
| 108 | 
            +
              # for example:
         | 
| 109 | 
            +
              #     CrowdFlower.connect!(default_api_key, development, version)
         | 
| 110 | 
            +
              #     (JobSubclass = Class.new(Job)).connect!(custom_api_key, development, version)
         | 
| 111 | 
            +
              #     job1 = Job.create('created with default api key')      
         | 
| 112 | 
            +
              #     job2 = JobSubclass.create('created with custom api key')
         | 
| 113 | 
            +
              class Base
         | 
| 114 | 
            +
             | 
| 115 | 
            +
                def initialize(new_connection = nil)
         | 
| 116 | 
            +
                  @connection = new_connection
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
                
         | 
| 119 | 
            +
                def connection
         | 
| 120 | 
            +
                  @connection or self.class.connection
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                def self.connection
         | 
| 124 | 
            +
                  default_connection or (self != Base and superclass.connection)
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
                
         | 
| 127 | 
            +
                class << self
         | 
| 128 | 
            +
                  attr_accessor :default_connection
         | 
| 44 129 | 
             
                end
         | 
| 45 | 
            -
              end
         | 
| 46 130 |  | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
             | 
| 131 | 
            +
                def self.connect!(key, development = false, version = 1)
         | 
| 132 | 
            +
                  domain_base = development ? "https://api.localdev.crowdflower.com:8443" : "https://api.crowdflower.com"
         | 
| 133 | 
            +
                  connect_domain!(key, domain_base, version)
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
                
         | 
| 136 | 
            +
                def self.connect_domain!(key, domain_base, version = 1)
         | 
| 137 | 
            +
                  self.default_connection = Connection.new(key, domain_base, version)
         | 
| 138 | 
            +
                end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                def self.connect_config!(opts)
         | 
| 141 | 
            +
                  extract_option = lambda do |arr|
         | 
| 142 | 
            +
                    arr.map { |k| opts[k] || opts[k.to_s] }.compact.first
         | 
| 143 | 
            +
                  end
         | 
| 144 | 
            +
                  key         = extract_option.call([:key, :api_key])
         | 
| 145 | 
            +
                  domain_base = extract_option.call([:domain_base, :domain])
         | 
| 146 | 
            +
                  version     = extract_option.call([:version])     || 1
         | 
| 147 | 
            +
                  ssl_port    = extract_option.call([:ssl_port])    || 443
         | 
| 148 | 
            +
                  public_port = extract_option.call([:public_port]) || 80
         | 
| 149 | 
            +
                  self.default_connection = Connection.new(key, domain_base, version, ssl_port, public_port)
         | 
| 150 | 
            +
                end
         | 
| 50 151 |  | 
| 51 | 
            -
             | 
| 52 | 
            -
                 | 
| 152 | 
            +
                def self.get(*args); connection.get(*args); end
         | 
| 153 | 
            +
                def self.post(*args); connection.post(*args); end
         | 
| 154 | 
            +
                def self.put(*args); connection.put(*args); end
         | 
| 155 | 
            +
                def self.delete(*args); connection.delete(*args); end
         | 
| 156 | 
            +
                
         | 
| 157 | 
            +
                def connect
         | 
| 158 | 
            +
                  unless connection
         | 
| 159 | 
            +
                    raise UsageError, "Please establish a connection using 'CrowdFlower.connect!'"
         | 
| 160 | 
            +
                  end
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                def self.connect
         | 
| 164 | 
            +
                  unless connection
         | 
| 165 | 
            +
                    raise UsageError, "Please establish a connection using 'CrowdFlower.connect!'"
         | 
| 166 | 
            +
                  end
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
             | 
| 169 | 
            +
               def self.verify_response(response)
         | 
| 170 | 
            +
                  if response["errors"]
         | 
| 171 | 
            +
                    raise CrowdFlower::APIError.new(response["errors"])
         | 
| 172 | 
            +
                  elsif response.response.kind_of? Net::HTTPUnauthorized
         | 
| 173 | 
            +
                    raise CrowdFlower::APIError.new('message' => response.to_s)
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
                
         | 
| 53 177 | 
             
              end
         | 
| 178 | 
            +
              
         | 
| 54 179 | 
             
            end
         | 
    
        data/lib/crowdflower/job.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 1 | 
             
            module CrowdFlower
         | 
| 2 | 
            -
              class Job
         | 
| 3 | 
            -
                include Defaults
         | 
| 2 | 
            +
              class Job < Base
         | 
| 4 3 | 
             
                attr_reader :id
         | 
| 5 4 |  | 
| 6 | 
            -
                def initialize(job_id)
         | 
| 5 | 
            +
                def initialize(job_id, connection = nil)
         | 
| 6 | 
            +
                  super connection
         | 
| 7 7 | 
             
                  @id = job_id
         | 
| 8 | 
            -
                   | 
| 8 | 
            +
                  connect
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 11 | 
             
                def resource_uri
         | 
| @@ -21,30 +21,30 @@ module CrowdFlower | |
| 21 21 | 
             
                  get(resource_uri)
         | 
| 22 22 | 
             
                end
         | 
| 23 23 |  | 
| 24 | 
            -
                def self.upload(file, content_type,  | 
| 24 | 
            +
                def self.upload(file, content_type, job = nil)
         | 
| 25 25 | 
             
                  connect
         | 
| 26 | 
            -
                   | 
| 27 | 
            -
                   | 
| 26 | 
            +
                  
         | 
| 27 | 
            +
                  job_uri = job ? "/#{job.kind_of?(Job) ? job.id : job}" : ""
         | 
| 28 | 
            +
                  conn = job.kind_of?(Job) ? job.connection : self.connection
         | 
| 29 | 
            +
                  upload_uri = "#{resource_uri}/#{job_uri}/upload".squeeze("/")
         | 
| 30 | 
            +
                  res = conn.post(upload_uri, 
         | 
| 28 31 | 
             
                    :body => File.read(file), 
         | 
| 29 | 
            -
                    :headers =>  | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
                   | 
| 33 | 
            -
                  Job.new(res["id"])
         | 
| 32 | 
            +
                    :headers => {"content-type" => content_type})
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                  verify_response res
         | 
| 35 | 
            +
                  job.kind_of?(Job) ? job : self.new(res["id"], conn)
         | 
| 34 36 | 
             
                end
         | 
| 35 37 |  | 
| 36 38 | 
             
                # Creates a new empty Job in CrowdFlower.
         | 
| 37 39 | 
             
                def self.create(title)
         | 
| 38 40 | 
             
                  connect
         | 
| 39 | 
            -
                  res = post("#{resource_uri}.json", :query => {:job => {:title => title } }, :headers => { "Content-Length" => "0" } )
         | 
| 40 | 
            -
                   | 
| 41 | 
            -
             | 
| 42 | 
            -
                  end
         | 
| 43 | 
            -
                  Job.new(res["id"])
         | 
| 41 | 
            +
                  res = self.post("#{resource_uri}.json", :query => {:job => {:title => title } }, :headers => { "Content-Length" => "0" } )
         | 
| 42 | 
            +
                  verify_response res
         | 
| 43 | 
            +
                  self.new(res["id"])
         | 
| 44 44 | 
             
                end
         | 
| 45 45 |  | 
| 46 46 | 
             
                def get(id = nil)
         | 
| 47 | 
            -
                   | 
| 47 | 
            +
                  connection.get("#{resource_uri}/#{@id || id}")
         | 
| 48 48 | 
             
                end
         | 
| 49 49 |  | 
| 50 50 | 
             
                # Returns an accessor for all the Units associated with this job.
         | 
| @@ -63,28 +63,27 @@ module CrowdFlower | |
| 63 63 | 
             
                #    gold: when set to true copies gold units
         | 
| 64 64 | 
             
                #    all_units: when set to true copies all units
         | 
| 65 65 | 
             
                def copy(opts = {})
         | 
| 66 | 
            -
                  res =  | 
| 67 | 
            -
                   | 
| 68 | 
            -
             | 
| 69 | 
            -
                  end
         | 
| 70 | 
            -
                  Job.new(res["id"])
         | 
| 66 | 
            +
                  res = connection.get("#{resource_uri}/#{@id}/copy", {:query => opts})
         | 
| 67 | 
            +
                  self.class.verify_response res
         | 
| 68 | 
            +
                  self.class.new(res["id"])
         | 
| 71 69 | 
             
                end
         | 
| 72 70 |  | 
| 73 71 | 
             
                def status
         | 
| 74 | 
            -
                   | 
| 72 | 
            +
                  connection.get("#{resource_uri}/#{@id}/ping")
         | 
| 75 73 | 
             
                end
         | 
| 76 74 |  | 
| 77 75 | 
             
                def upload(file, content_type)
         | 
| 78 | 
            -
                   | 
| 76 | 
            +
                  self.class.upload(file, content_type, self)
         | 
| 79 77 | 
             
                end
         | 
| 80 78 |  | 
| 81 79 | 
             
                def legend
         | 
| 82 | 
            -
                   | 
| 80 | 
            +
                  connection.get("#{resource_uri}/#{@id}/legend")
         | 
| 83 81 | 
             
                end
         | 
| 84 82 |  | 
| 85 83 | 
             
                def download_csv(type = :full, filename = nil)
         | 
| 86 84 | 
             
                  filename ||= "#{type.to_s[0].chr}#{@id}.csv"
         | 
| 87 | 
            -
                  res =  | 
| 85 | 
            +
                  res = connection.get("#{resource_uri}/#{@id}.csv", {:format => :csv, :query => {:type => type}})
         | 
| 86 | 
            +
                  self.class.verify_response res
         | 
| 88 87 | 
             
                  puts "Status... #{res.code.inspect}"
         | 
| 89 88 | 
             
                  if res.code == 202
         | 
| 90 89 | 
             
                    puts "CSV Generating... Trying again in 10 seconds."
         | 
| @@ -97,40 +96,34 @@ module CrowdFlower | |
| 97 96 | 
             
                end
         | 
| 98 97 |  | 
| 99 98 | 
             
                def pause
         | 
| 100 | 
            -
                   | 
| 99 | 
            +
                  connection.get("#{resource_uri}/#{@id}/pause")
         | 
| 101 100 | 
             
                end
         | 
| 102 101 |  | 
| 103 102 | 
             
                def resume
         | 
| 104 | 
            -
                   | 
| 103 | 
            +
                  connection.get("#{resource_uri}/#{@id}/resume")
         | 
| 105 104 | 
             
                end
         | 
| 106 105 |  | 
| 107 106 | 
             
                def cancel
         | 
| 108 | 
            -
                   | 
| 107 | 
            +
                  connection.get("#{resource_uri}/#{@id}/cancel")
         | 
| 109 108 | 
             
                end
         | 
| 110 109 |  | 
| 111 110 | 
             
                def update(data)
         | 
| 112 | 
            -
                   | 
| 113 | 
            -
                   | 
| 114 | 
            -
             | 
| 115 | 
            -
                  end
         | 
| 111 | 
            +
                  response = connection.put("#{resource_uri}/#{@id}.json", {:body => { :job => data }, :headers => { "Content-Length" => "0" } } )
         | 
| 112 | 
            +
                  self.class.verify_response(response)
         | 
| 113 | 
            +
                  response
         | 
| 116 114 | 
             
                end
         | 
| 117 115 |  | 
| 118 116 | 
             
                def delete
         | 
| 119 | 
            -
                   | 
| 117 | 
            +
                  connection.delete("#{resource_uri}/#{@id}.json")
         | 
| 120 118 | 
             
                end
         | 
| 121 119 |  | 
| 122 120 | 
             
                def channels
         | 
| 123 | 
            -
                   | 
| 121 | 
            +
                  connection.get("#{resource_uri}/#{@id}/channels")
         | 
| 124 122 | 
             
                end
         | 
| 125 123 |  | 
| 126 124 | 
             
                def enable_channels(channels)
         | 
| 127 | 
            -
                   | 
| 125 | 
            +
                  connection.post("#{resource_uri}/#{@id}/channels", {:body => { :channels => channels } } )
         | 
| 128 126 | 
             
                end
         | 
| 129 127 |  | 
| 130 | 
            -
                private
         | 
| 131 | 
            -
                def self.custom_content_type(content_type)
         | 
| 132 | 
            -
                  #To preserve the accept header we are forced to merge the defaults back in...
         | 
| 133 | 
            -
                  Job.default_options[:headers].merge({"content-type" => content_type})
         | 
| 134 | 
            -
                end
         | 
| 135 128 | 
             
              end
         | 
| 136 129 | 
             
            end
         | 
    
        data/lib/crowdflower/judgment.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 1 | 
             
            module CrowdFlower
         | 
| 2 | 
            -
              class Judgment
         | 
| 3 | 
            -
                include Defaults
         | 
| 2 | 
            +
              class Judgment < Base
         | 
| 4 3 | 
             
                attr_reader :job
         | 
| 5 4 |  | 
| 6 5 | 
             
                def initialize(job)
         | 
| 6 | 
            +
                  super job.connection
         | 
| 7 7 | 
             
                  @job = job
         | 
| 8 | 
            -
                   | 
| 8 | 
            +
                  connect
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 11 | 
             
                def resource_uri
         | 
| @@ -13,13 +13,32 @@ module CrowdFlower | |
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                #Pull every judgment
         | 
| 16 | 
            -
                def all(page = 1, limit = 100, latest = true) | 
| 17 | 
            -
                  opts =  | 
| 18 | 
            -
                   | 
| 16 | 
            +
                def all(page = 1, limit = 100, latest = true)
         | 
| 17 | 
            +
                  opts = CrowdFlower.version == 2 ? {:unseen => latest} : {:latest => latest}
         | 
| 18 | 
            +
                  get(resource_uri, {:query => {:limit => limit, :page => page}.merge(opts)})
         | 
| 19 19 | 
             
                end
         | 
| 20 20 |  | 
| 21 21 | 
             
                def get(id)
         | 
| 22 | 
            -
                   | 
| 22 | 
            +
                  get("#{resource_uri}/#{id}")
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                # Reject an individual Judgment.
         | 
| 26 | 
            +
                # 
         | 
| 27 | 
            +
                # *Admin-only && MTurk-only*
         | 
| 28 | 
            +
                # 
         | 
| 29 | 
            +
                # @param [String,Integer] id The CrowdFlower id for the judgment to reject.
         | 
| 30 | 
            +
                def reject( id )
         | 
| 31 | 
            +
                  put( "#{resource_uri}/#{id}/reject" )
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                
         | 
| 34 | 
            +
                protected
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                def put( *args )
         | 
| 37 | 
            +
                  connection.put *args
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
                
         | 
| 40 | 
            +
                def get( *args )
         | 
| 41 | 
            +
                  connection.get *args
         | 
| 23 42 | 
             
                end
         | 
| 24 43 | 
             
              end
         | 
| 25 | 
            -
            end
         | 
| 44 | 
            +
            end
         | 
    
        data/lib/crowdflower/order.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 1 | 
             
            module CrowdFlower
         | 
| 2 | 
            -
              class Order
         | 
| 3 | 
            -
                include Defaults
         | 
| 2 | 
            +
              class Order < Base
         | 
| 4 3 | 
             
                attr_reader :job
         | 
| 5 4 |  | 
| 6 5 | 
             
                def initialize(job)
         | 
| 6 | 
            +
                  super job.connection
         | 
| 7 7 | 
             
                  @job = job
         | 
| 8 | 
            -
                   | 
| 8 | 
            +
                  connect
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 11 | 
             
                def resource_uri
         | 
| @@ -13,7 +13,7 @@ module CrowdFlower | |
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                def debit(units_count = 1, channels = ["amt"])
         | 
| 16 | 
            -
                   | 
| 16 | 
            +
                  connection.post(resource_uri, {:query => {:debit => {:units_count => units_count}, :channels => channels}})
         | 
| 17 17 | 
             
                end
         | 
| 18 18 | 
             
              end
         | 
| 19 19 | 
             
            end
         | 
    
        data/lib/crowdflower/unit.rb
    CHANGED
    
    | @@ -1,11 +1,11 @@ | |
| 1 1 | 
             
            module CrowdFlower
         | 
| 2 | 
            -
              class Unit
         | 
| 3 | 
            -
                include Defaults
         | 
| 2 | 
            +
              class Unit < Base
         | 
| 4 3 | 
             
                attr_reader :job
         | 
| 5 4 |  | 
| 6 5 | 
             
                def initialize(job)
         | 
| 6 | 
            +
                  super job.connection
         | 
| 7 7 | 
             
                  @job = job
         | 
| 8 | 
            -
                   | 
| 8 | 
            +
                  connect
         | 
| 9 9 | 
             
                end
         | 
| 10 10 |  | 
| 11 11 | 
             
                def resource_uri
         | 
| @@ -13,35 +13,35 @@ module CrowdFlower | |
| 13 13 | 
             
                end
         | 
| 14 14 |  | 
| 15 15 | 
             
                def all(page = 1, limit = 1000)
         | 
| 16 | 
            -
                   | 
| 16 | 
            +
                  connection.get(resource_uri, {:query => {:limit => limit, :page => page}})
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 19 | 
             
                def get(id)
         | 
| 20 | 
            -
                   | 
| 20 | 
            +
                  connection.get("#{resource_uri}/#{id}")
         | 
| 21 21 | 
             
                end
         | 
| 22 22 |  | 
| 23 23 | 
             
                def ping
         | 
| 24 | 
            -
                   | 
| 24 | 
            +
                  connection.get("#{resource_uri}/ping")
         | 
| 25 25 | 
             
                end
         | 
| 26 26 |  | 
| 27 27 | 
             
                def judgments(id)
         | 
| 28 | 
            -
                   | 
| 28 | 
            +
                  connection.get("#{resource_uri}/#{id}/judgments")
         | 
| 29 29 | 
             
                end
         | 
| 30 30 |  | 
| 31 31 | 
             
                def create(data, gold = false)
         | 
| 32 | 
            -
                   | 
| 32 | 
            +
                  connection.post(resource_uri, {:query => {:unit => {:data => data.to_json, :golden => gold}}})
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                def copy(unit_id, job_id, data = {})
         | 
| 36 | 
            -
                   | 
| 36 | 
            +
                  connection.get("#{resource_uri}/#{unit_id}/copy", {:query => {:unit => {:job_id => job_id, :data => data}}})
         | 
| 37 37 | 
             
                end
         | 
| 38 38 |  | 
| 39 39 | 
             
                def split(on, with = " ")
         | 
| 40 | 
            -
                   | 
| 40 | 
            +
                  connection.get("#{resource_uri}/split", {:query => {:on => on, :with => with}})
         | 
| 41 41 | 
             
                end
         | 
| 42 42 |  | 
| 43 43 | 
             
                def cancel(unit_id)
         | 
| 44 | 
            -
                   | 
| 44 | 
            +
                  connection.post("#{resource_uri}/#{unit_id}/cancel.json")
         | 
| 45 45 | 
             
                end
         | 
| 46 46 | 
             
              end
         | 
| 47 47 | 
             
            end
         | 
| @@ -0,0 +1,54 @@ | |
| 1 | 
            +
            module CrowdFlower
         | 
| 2 | 
            +
              class Worker < Base
         | 
| 3 | 
            +
                attr_reader :job
         | 
| 4 | 
            +
                
         | 
| 5 | 
            +
                def initialize( job )
         | 
| 6 | 
            +
                  super job.connection
         | 
| 7 | 
            +
                  @job = job
         | 
| 8 | 
            +
                  connect
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
                
         | 
| 11 | 
            +
                def resource_uri
         | 
| 12 | 
            +
                  "/jobs/#{@job.id}/workers"
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                def bonus( worker_id, amount, reason=nil )
         | 
| 16 | 
            +
                  params = { :amount => amount }
         | 
| 17 | 
            +
                  params.merge!( :reason => reason ) if reason
         | 
| 18 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/bonus", :body => params )
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
                
         | 
| 21 | 
            +
                def approve( worker_id )
         | 
| 22 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/approve" )
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
                
         | 
| 25 | 
            +
                def reject( worker_id )
         | 
| 26 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/reject" )
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
                
         | 
| 29 | 
            +
                def ban( worker_id )
         | 
| 30 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/ban" )
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
                
         | 
| 33 | 
            +
                def deban( worker_id )
         | 
| 34 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/deban" )
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
                
         | 
| 37 | 
            +
                def notify( worker_id, subject, message )
         | 
| 38 | 
            +
                  params = {
         | 
| 39 | 
            +
                    :subject => subject,
         | 
| 40 | 
            +
                    :message => message
         | 
| 41 | 
            +
                  }
         | 
| 42 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/notify", :body => params )
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
                
         | 
| 45 | 
            +
                def flag( worker_id, reason )
         | 
| 46 | 
            +
                  params = reason ? { :reason => reason } : nil
         | 
| 47 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/flag", :body => params )
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
                
         | 
| 50 | 
            +
                def deflag( worker_id )
         | 
| 51 | 
            +
                  connection.put( "#{resource_uri}/#{worker_id}/deflag" )
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
              end
         | 
| 54 | 
            +
            end
         | 
    
        data/test/integration_tests.rb
    CHANGED
    
    | @@ -36,7 +36,7 @@ def wait_until | |
| 36 36 | 
             
                if yield
         | 
| 37 37 | 
             
                  return
         | 
| 38 38 | 
             
                end
         | 
| 39 | 
            -
                sleep  | 
| 39 | 
            +
                sleep 5 
         | 
| 40 40 | 
             
              end
         | 
| 41 41 | 
             
              raise "Condition not met in a reasonable time period"
         | 
| 42 42 | 
             
            end
         | 
| @@ -47,13 +47,48 @@ def assert(truth) | |
| 47 47 | 
             
              end
         | 
| 48 48 | 
             
            end
         | 
| 49 49 |  | 
| 50 | 
            +
            def assert_exception_raised expected_exception_class
         | 
| 51 | 
            +
              begin
         | 
| 52 | 
            +
                yield
         | 
| 53 | 
            +
              rescue expected_exception_class
         | 
| 54 | 
            +
                return
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
              raise "exception #{expected_ex} has not been raised"
         | 
| 57 | 
            +
            end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
             | 
| 50 60 | 
             
            def say(msg)
         | 
| 51 61 | 
             
              $stdout.puts msg
         | 
| 52 62 | 
             
            end
         | 
| 53 63 |  | 
| 64 | 
            +
             | 
| 65 | 
            +
            say "defining multiple api keys"
         | 
| 66 | 
            +
            (job_subclass_with_valid_custom_key = Class.new(CrowdFlower::Job)).connect! API_KEY, true
         | 
| 67 | 
            +
            (job_subclass_with_invalid_custom_key = Class.new(CrowdFlower::Job)).connect! 'invalid api key', true
         | 
| 68 | 
            +
            job_subclass_with_no_custom_key = Class.new(CrowdFlower::Job)
         | 
| 69 | 
            +
             | 
| 70 | 
            +
            say "no default api key"
         | 
| 71 | 
            +
            assert_exception_raised(CrowdFlower::UsageError) {CrowdFlower::Job.create("job creation should fail")}
         | 
| 72 | 
            +
            assert_exception_raised(CrowdFlower::UsageError) {job_subclass_with_no_custom_key.create("job creation should fail")}
         | 
| 73 | 
            +
            assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_invalid_custom_key.create("job creation should fail")}
         | 
| 74 | 
            +
            assert job_subclass_with_valid_custom_key.create("should be ok").units.ping['count']
         | 
| 75 | 
            +
             | 
| 76 | 
            +
            say "invalid default api key"
         | 
| 77 | 
            +
            CrowdFlower.connect! "invalid default api key", true
         | 
| 78 | 
            +
            assert_exception_raised(CrowdFlower::APIError) {CrowdFlower::Job.create("job creation should fail")}
         | 
| 79 | 
            +
            assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_no_custom_key.create("job creation should fail")}
         | 
| 80 | 
            +
            assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_invalid_custom_key.create("job creation should fail")}
         | 
| 81 | 
            +
            assert job_subclass_with_valid_custom_key.create("should be ok").units.ping['count']
         | 
| 82 | 
            +
             | 
| 54 83 | 
             
            say "Connecting to the API"
         | 
| 55 84 | 
             
            CrowdFlower.connect! API_KEY, true
         | 
| 56 85 |  | 
| 86 | 
            +
            assert CrowdFlower::Job.create("should be ok").units.ping['count']
         | 
| 87 | 
            +
            assert job_subclass_with_no_custom_key.create("should be ok").units.ping['count']
         | 
| 88 | 
            +
            assert job_subclass_with_valid_custom_key.create("should be ok").units.ping['count']
         | 
| 89 | 
            +
            assert_exception_raised(CrowdFlower::APIError) {job_subclass_with_invalid_custom_key.create("job creation should fail")}
         | 
| 90 | 
            +
            assert CrowdFlower::Base.connection.public_url == "localdev.crowdflower.com:80"
         | 
| 91 | 
            +
             | 
| 57 92 | 
             
            say "Uploading a test CSV"
         | 
| 58 93 | 
             
            job = CrowdFlower::Job.upload(File.dirname(__FILE__) + "/sample.csv", "text/csv")
         | 
| 59 94 |  | 
    
        metadata
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: crowdflower
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              hash:  | 
| 5 | 
            -
              prerelease:  | 
| 4 | 
            +
              hash: 13
         | 
| 5 | 
            +
              prerelease: 
         | 
| 6 6 | 
             
              segments: 
         | 
| 7 7 | 
             
              - 0
         | 
| 8 | 
            -
              - 4
         | 
| 9 8 | 
             
              - 5
         | 
| 10 | 
            -
               | 
| 9 | 
            +
              - 3
         | 
| 10 | 
            +
              version: 0.5.3
         | 
| 11 11 | 
             
            platform: ruby
         | 
| 12 12 | 
             
            authors: 
         | 
| 13 13 | 
             
            - Brian P O'Rourke
         | 
| @@ -16,7 +16,7 @@ autorequire: | |
| 16 16 | 
             
            bindir: bin
         | 
| 17 17 | 
             
            cert_chain: []
         | 
| 18 18 |  | 
| 19 | 
            -
            date:  | 
| 19 | 
            +
            date: 2011-02-10 00:00:00 -08:00
         | 
| 20 20 | 
             
            default_executable: 
         | 
| 21 21 | 
             
            dependencies: 
         | 
| 22 22 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -50,7 +50,6 @@ extra_rdoc_files: | |
| 50 50 | 
             
            - README.md
         | 
| 51 51 | 
             
            files: 
         | 
| 52 52 | 
             
            - .document
         | 
| 53 | 
            -
            - .gitignore
         | 
| 54 53 | 
             
            - CONTRIBUTORS
         | 
| 55 54 | 
             
            - HISTORY.md
         | 
| 56 55 | 
             
            - LICENSE
         | 
| @@ -66,6 +65,7 @@ files: | |
| 66 65 | 
             
            - lib/crowdflower/judgment.rb
         | 
| 67 66 | 
             
            - lib/crowdflower/order.rb
         | 
| 68 67 | 
             
            - lib/crowdflower/unit.rb
         | 
| 68 | 
            +
            - lib/crowdflower/worker.rb
         | 
| 69 69 | 
             
            - test/integration_tests.rb
         | 
| 70 70 | 
             
            - test/sample.csv
         | 
| 71 71 | 
             
            has_rdoc: true
         | 
| @@ -73,8 +73,8 @@ homepage: http://github.com/dolores/ruby-crowdflower | |
| 73 73 | 
             
            licenses: []
         | 
| 74 74 |  | 
| 75 75 | 
             
            post_install_message: 
         | 
| 76 | 
            -
            rdoc_options: 
         | 
| 77 | 
            -
             | 
| 76 | 
            +
            rdoc_options: []
         | 
| 77 | 
            +
             | 
| 78 78 | 
             
            require_paths: 
         | 
| 79 79 | 
             
            - lib
         | 
| 80 80 | 
             
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| @@ -98,7 +98,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 98 98 | 
             
            requirements: []
         | 
| 99 99 |  | 
| 100 100 | 
             
            rubyforge_project: 
         | 
| 101 | 
            -
            rubygems_version: 1. | 
| 101 | 
            +
            rubygems_version: 1.4.2
         | 
| 102 102 | 
             
            signing_key: 
         | 
| 103 103 | 
             
            specification_version: 3
         | 
| 104 104 | 
             
            summary: a toolkit for the CrowdFlower API
         |