ex_twitter 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/README.md +0 -8
 - data/ex_twitter.gemspec +1 -1
 - data/lib/ex_twitter/client.rb +194 -0
 - data/lib/ex_twitter/existing_api.rb +122 -0
 - data/lib/ex_twitter/log_subscriber.rb +79 -0
 - data/lib/ex_twitter/new_api.rb +238 -0
 - data/lib/ex_twitter/utils.rb +293 -0
 - data/lib/ex_twitter.rb +1 -805
 - metadata +7 -4
 - data/lib/ex_stream.rb +0 -68
 - data/lib/ex_twitter_subscriber.rb +0 -8
 
| 
         @@ -0,0 +1,293 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module ExTwitter
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Utils
         
     | 
| 
      
 3 
     | 
    
         
            +
                # for backward compatibility
         
     | 
| 
      
 4 
     | 
    
         
            +
                def uid
         
     | 
| 
      
 5 
     | 
    
         
            +
                  user.id
         
     | 
| 
      
 6 
     | 
    
         
            +
                end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                def __uid
         
     | 
| 
      
 9 
     | 
    
         
            +
                  uid
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def __uid_i
         
     | 
| 
      
 13 
     | 
    
         
            +
                  uid.to_i
         
     | 
| 
      
 14 
     | 
    
         
            +
                end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                # for backward compatibility
         
     | 
| 
      
 17 
     | 
    
         
            +
                def screen_name
         
     | 
| 
      
 18 
     | 
    
         
            +
                  user.screen_name
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                def __screen_name
         
     | 
| 
      
 22 
     | 
    
         
            +
                  screen_name
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                def uid_or_screen_name?(object)
         
     | 
| 
      
 26 
     | 
    
         
            +
                  object.kind_of?(String) || object.kind_of?(Integer)
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                def authenticating_user?(target)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  user.id.to_i == user(target).id.to_i
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                def authorized_user?(target)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  target_user = user(target)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  !target_user.protected? || friendship?(user.id.to_i, target_user.id.to_i)
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                def instrument(operation, key, options = nil)
         
     | 
| 
      
 39 
     | 
    
         
            +
                  payload = {operation: operation, key: key}
         
     | 
| 
      
 40 
     | 
    
         
            +
                  payload.merge!(options) if options.is_a?(Hash)
         
     | 
| 
      
 41 
     | 
    
         
            +
                  ActiveSupport::Notifications.instrument('call.ex_twitter', payload) { yield(payload) }
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                def call_old_method(method_name, *args)
         
     | 
| 
      
 45 
     | 
    
         
            +
                  options = args.extract_options!
         
     | 
| 
      
 46 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 47 
     | 
    
         
            +
                    self.call_count += 1
         
     | 
| 
      
 48 
     | 
    
         
            +
                    _options = {method_name: method_name, call_count: self.call_count, args: args}.merge(options)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    instrument('api call', args[0], _options) { send(method_name, *args, options) }
         
     | 
| 
      
 50 
     | 
    
         
            +
                  rescue Twitter::Error::TooManyRequests => e
         
     | 
| 
      
 51 
     | 
    
         
            +
                    logger.warn "#{__method__}: call=#{method_name} #{args.inspect} #{e.class} Retry after #{e.rate_limit.reset_in} seconds."
         
     | 
| 
      
 52 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 53 
     | 
    
         
            +
                  rescue Twitter::Error::ServiceUnavailable => e
         
     | 
| 
      
 54 
     | 
    
         
            +
                    logger.warn "#{__method__}: call=#{method_name} #{args.inspect} #{e.class} #{e.message}"
         
     | 
| 
      
 55 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 56 
     | 
    
         
            +
                  rescue Twitter::Error::InternalServerError => e
         
     | 
| 
      
 57 
     | 
    
         
            +
                    logger.warn "#{__method__}: call=#{method_name} #{args.inspect} #{e.class} #{e.message}"
         
     | 
| 
      
 58 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 59 
     | 
    
         
            +
                  rescue Twitter::Error::Forbidden => e
         
     | 
| 
      
 60 
     | 
    
         
            +
                    logger.warn "#{__method__}: call=#{method_name} #{args.inspect} #{e.class} #{e.message}"
         
     | 
| 
      
 61 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 62 
     | 
    
         
            +
                  rescue Twitter::Error::NotFound => e
         
     | 
| 
      
 63 
     | 
    
         
            +
                    logger.warn "#{__method__}: call=#{method_name} #{args.inspect} #{e.class} #{e.message}"
         
     | 
| 
      
 64 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 65 
     | 
    
         
            +
                  rescue => e
         
     | 
| 
      
 66 
     | 
    
         
            +
                    logger.warn "#{__method__}: call=#{method_name} #{args.inspect} #{e.class} #{e.message}"
         
     | 
| 
      
 67 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                # user_timeline, search
         
     | 
| 
      
 72 
     | 
    
         
            +
                def collect_with_max_id(method_name, *args)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  options = args.extract_options!
         
     | 
| 
      
 74 
     | 
    
         
            +
                  call_limit = options.delete(:call_limit) || 3
         
     | 
| 
      
 75 
     | 
    
         
            +
                  last_response = call_old_method(method_name, *args, options)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  last_response = yield(last_response) if block_given?
         
     | 
| 
      
 77 
     | 
    
         
            +
                  return_data = last_response
         
     | 
| 
      
 78 
     | 
    
         
            +
                  call_count = 1
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  while last_response.any? && call_count < call_limit
         
     | 
| 
      
 81 
     | 
    
         
            +
                    options[:max_id] = last_response.last.kind_of?(Hash) ? last_response.last[:id] : last_response.last.id
         
     | 
| 
      
 82 
     | 
    
         
            +
                    last_response = call_old_method(method_name, *args, options)
         
     | 
| 
      
 83 
     | 
    
         
            +
                    last_response = yield(last_response) if block_given?
         
     | 
| 
      
 84 
     | 
    
         
            +
                    return_data += last_response
         
     | 
| 
      
 85 
     | 
    
         
            +
                    call_count += 1
         
     | 
| 
      
 86 
     | 
    
         
            +
                  end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                  return_data.flatten
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                # friends, followers
         
     | 
| 
      
 92 
     | 
    
         
            +
                def collect_with_cursor(method_name, *args)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  options = args.extract_options!
         
     | 
| 
      
 94 
     | 
    
         
            +
                  last_response = call_old_method(method_name, *args, options).attrs
         
     | 
| 
      
 95 
     | 
    
         
            +
                  return_data = (last_response[:users] || last_response[:ids])
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                  while (next_cursor = last_response[:next_cursor]) && next_cursor != 0
         
     | 
| 
      
 98 
     | 
    
         
            +
                    options[:cursor] = next_cursor
         
     | 
| 
      
 99 
     | 
    
         
            +
                    last_response = call_old_method(method_name, *args, options).attrs
         
     | 
| 
      
 100 
     | 
    
         
            +
                    return_data += (last_response[:users] || last_response[:ids])
         
     | 
| 
      
 101 
     | 
    
         
            +
                  end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                  return_data
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                require 'digest/md5'
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                def file_cache_key(method_name, user, options = {})
         
     | 
| 
      
 109 
     | 
    
         
            +
                  delim = ':'
         
     | 
| 
      
 110 
     | 
    
         
            +
                  identifier =
         
     | 
| 
      
 111 
     | 
    
         
            +
                    case
         
     | 
| 
      
 112 
     | 
    
         
            +
                      when method_name == :search
         
     | 
| 
      
 113 
     | 
    
         
            +
                        "str#{delim}#{user.to_s}"
         
     | 
| 
      
 114 
     | 
    
         
            +
                      when method_name == :mentions_timeline
         
     | 
| 
      
 115 
     | 
    
         
            +
                        "#{user.kind_of?(Integer) ? 'id' : 'sn'}#{delim}#{user.to_s}"
         
     | 
| 
      
 116 
     | 
    
         
            +
                      when method_name == :home_timeline
         
     | 
| 
      
 117 
     | 
    
         
            +
                        "#{user.kind_of?(Integer) ? 'id' : 'sn'}#{delim}#{user.to_s}"
         
     | 
| 
      
 118 
     | 
    
         
            +
                      when method_name.in?([:users, :replying]) && options[:super_operation].present?
         
     | 
| 
      
 119 
     | 
    
         
            +
                        case
         
     | 
| 
      
 120 
     | 
    
         
            +
                          when user.kind_of?(Array) && user.first.kind_of?(Integer)
         
     | 
| 
      
 121 
     | 
    
         
            +
                            "#{options[:super_operation]}-ids#{delim}#{Digest::MD5.hexdigest(user.join(','))}"
         
     | 
| 
      
 122 
     | 
    
         
            +
                          when user.kind_of?(Array) && user.first.kind_of?(String)
         
     | 
| 
      
 123 
     | 
    
         
            +
                            "#{options[:super_operation]}-sns#{delim}#{Digest::MD5.hexdigest(user.join(','))}"
         
     | 
| 
      
 124 
     | 
    
         
            +
                          else raise "#{method_name.inspect} #{user.inspect}"
         
     | 
| 
      
 125 
     | 
    
         
            +
                        end
         
     | 
| 
      
 126 
     | 
    
         
            +
                      when user.kind_of?(Integer)
         
     | 
| 
      
 127 
     | 
    
         
            +
                        "id#{delim}#{user.to_s}"
         
     | 
| 
      
 128 
     | 
    
         
            +
                      when user.kind_of?(Array) && user.first.kind_of?(Integer)
         
     | 
| 
      
 129 
     | 
    
         
            +
                        "ids#{delim}#{Digest::MD5.hexdigest(user.join(','))}"
         
     | 
| 
      
 130 
     | 
    
         
            +
                      when user.kind_of?(Array) && user.first.kind_of?(String)
         
     | 
| 
      
 131 
     | 
    
         
            +
                        "sns#{delim}#{Digest::MD5.hexdigest(user.join(','))}"
         
     | 
| 
      
 132 
     | 
    
         
            +
                      when user.kind_of?(String)
         
     | 
| 
      
 133 
     | 
    
         
            +
                        "sn#{delim}#{user}"
         
     | 
| 
      
 134 
     | 
    
         
            +
                      when user.kind_of?(Twitter::User)
         
     | 
| 
      
 135 
     | 
    
         
            +
                        "user#{delim}#{user.id.to_s}"
         
     | 
| 
      
 136 
     | 
    
         
            +
                      else raise "#{method_name.inspect} #{user.inspect}"
         
     | 
| 
      
 137 
     | 
    
         
            +
                    end
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                  "#{method_name}#{delim}#{identifier}"
         
     | 
| 
      
 140 
     | 
    
         
            +
                end
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                def namespaced_key(method_name, user, options = {})
         
     | 
| 
      
 143 
     | 
    
         
            +
                  file_cache_key(method_name, user, options)
         
     | 
| 
      
 144 
     | 
    
         
            +
                end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                PROFILE_SAVE_KEYS = %i(
         
     | 
| 
      
 147 
     | 
    
         
            +
                    id
         
     | 
| 
      
 148 
     | 
    
         
            +
                    name
         
     | 
| 
      
 149 
     | 
    
         
            +
                    screen_name
         
     | 
| 
      
 150 
     | 
    
         
            +
                    location
         
     | 
| 
      
 151 
     | 
    
         
            +
                    description
         
     | 
| 
      
 152 
     | 
    
         
            +
                    url
         
     | 
| 
      
 153 
     | 
    
         
            +
                    protected
         
     | 
| 
      
 154 
     | 
    
         
            +
                    followers_count
         
     | 
| 
      
 155 
     | 
    
         
            +
                    friends_count
         
     | 
| 
      
 156 
     | 
    
         
            +
                    listed_count
         
     | 
| 
      
 157 
     | 
    
         
            +
                    favourites_count
         
     | 
| 
      
 158 
     | 
    
         
            +
                    utc_offset
         
     | 
| 
      
 159 
     | 
    
         
            +
                    time_zone
         
     | 
| 
      
 160 
     | 
    
         
            +
                    geo_enabled
         
     | 
| 
      
 161 
     | 
    
         
            +
                    verified
         
     | 
| 
      
 162 
     | 
    
         
            +
                    statuses_count
         
     | 
| 
      
 163 
     | 
    
         
            +
                    lang
         
     | 
| 
      
 164 
     | 
    
         
            +
                    status
         
     | 
| 
      
 165 
     | 
    
         
            +
                    profile_image_url_https
         
     | 
| 
      
 166 
     | 
    
         
            +
                    profile_banner_url
         
     | 
| 
      
 167 
     | 
    
         
            +
                    profile_link_color
         
     | 
| 
      
 168 
     | 
    
         
            +
                    suspended
         
     | 
| 
      
 169 
     | 
    
         
            +
                    verified
         
     | 
| 
      
 170 
     | 
    
         
            +
                    entities
         
     | 
| 
      
 171 
     | 
    
         
            +
                    created_at
         
     | 
| 
      
 172 
     | 
    
         
            +
                  )
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
      
 174 
     | 
    
         
            +
                STATUS_SAVE_KEYS = %i(
         
     | 
| 
      
 175 
     | 
    
         
            +
                  created_at
         
     | 
| 
      
 176 
     | 
    
         
            +
                  id
         
     | 
| 
      
 177 
     | 
    
         
            +
                  text
         
     | 
| 
      
 178 
     | 
    
         
            +
                  source
         
     | 
| 
      
 179 
     | 
    
         
            +
                  truncated
         
     | 
| 
      
 180 
     | 
    
         
            +
                  coordinates
         
     | 
| 
      
 181 
     | 
    
         
            +
                  place
         
     | 
| 
      
 182 
     | 
    
         
            +
                  entities
         
     | 
| 
      
 183 
     | 
    
         
            +
                  user
         
     | 
| 
      
 184 
     | 
    
         
            +
                  contributors
         
     | 
| 
      
 185 
     | 
    
         
            +
                  is_quote_status
         
     | 
| 
      
 186 
     | 
    
         
            +
                  retweet_count
         
     | 
| 
      
 187 
     | 
    
         
            +
                  favorite_count
         
     | 
| 
      
 188 
     | 
    
         
            +
                  favorited
         
     | 
| 
      
 189 
     | 
    
         
            +
                  retweeted
         
     | 
| 
      
 190 
     | 
    
         
            +
                  possibly_sensitive
         
     | 
| 
      
 191 
     | 
    
         
            +
                  lang
         
     | 
| 
      
 192 
     | 
    
         
            +
                )
         
     | 
| 
      
 193 
     | 
    
         
            +
             
     | 
| 
      
 194 
     | 
    
         
            +
                # encode
         
     | 
| 
      
 195 
     | 
    
         
            +
                def encode_json(obj, caller_name, options = {})
         
     | 
| 
      
 196 
     | 
    
         
            +
                  options[:reduce] = true unless options.has_key?(:reduce)
         
     | 
| 
      
 197 
     | 
    
         
            +
                  result =
         
     | 
| 
      
 198 
     | 
    
         
            +
                    case caller_name
         
     | 
| 
      
 199 
     | 
    
         
            +
                      when :user_timeline, :home_timeline, :mentions_timeline, :favorites # Twitter::Tweet
         
     | 
| 
      
 200 
     | 
    
         
            +
                        JSON.pretty_generate(obj.map { |o| o.attrs })
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
                      when :search # Hash
         
     | 
| 
      
 203 
     | 
    
         
            +
                        data =
         
     | 
| 
      
 204 
     | 
    
         
            +
                          if options[:reduce]
         
     | 
| 
      
 205 
     | 
    
         
            +
                            obj.map { |o| o.to_hash.slice(*STATUS_SAVE_KEYS) }
         
     | 
| 
      
 206 
     | 
    
         
            +
                          else
         
     | 
| 
      
 207 
     | 
    
         
            +
                            obj.map { |o| o.to_hash }
         
     | 
| 
      
 208 
     | 
    
         
            +
                          end
         
     | 
| 
      
 209 
     | 
    
         
            +
                        JSON.pretty_generate(data)
         
     | 
| 
      
 210 
     | 
    
         
            +
             
     | 
| 
      
 211 
     | 
    
         
            +
                      when :friends, :followers # Hash
         
     | 
| 
      
 212 
     | 
    
         
            +
                        data =
         
     | 
| 
      
 213 
     | 
    
         
            +
                          if options[:reduce]
         
     | 
| 
      
 214 
     | 
    
         
            +
                            obj.map { |o| o.to_hash.slice(*PROFILE_SAVE_KEYS) }
         
     | 
| 
      
 215 
     | 
    
         
            +
                          else
         
     | 
| 
      
 216 
     | 
    
         
            +
                            obj.map { |o| o.to_hash }
         
     | 
| 
      
 217 
     | 
    
         
            +
                          end
         
     | 
| 
      
 218 
     | 
    
         
            +
                        JSON.pretty_generate(data)
         
     | 
| 
      
 219 
     | 
    
         
            +
             
     | 
| 
      
 220 
     | 
    
         
            +
                      when :friend_ids, :follower_ids # Integer
         
     | 
| 
      
 221 
     | 
    
         
            +
                        JSON.pretty_generate(obj)
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
                      when :user # Twitter::User
         
     | 
| 
      
 224 
     | 
    
         
            +
                        JSON.pretty_generate(obj.to_hash.slice(*PROFILE_SAVE_KEYS))
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                      when :users, :friends_parallelly, :followers_parallelly # Twitter::User
         
     | 
| 
      
 227 
     | 
    
         
            +
                        data =
         
     | 
| 
      
 228 
     | 
    
         
            +
                          if options[:reduce]
         
     | 
| 
      
 229 
     | 
    
         
            +
                            obj.map { |o| o.to_hash.slice(*PROFILE_SAVE_KEYS) }
         
     | 
| 
      
 230 
     | 
    
         
            +
                          else
         
     | 
| 
      
 231 
     | 
    
         
            +
                            obj.map { |o| o.to_hash }
         
     | 
| 
      
 232 
     | 
    
         
            +
                          end
         
     | 
| 
      
 233 
     | 
    
         
            +
                        JSON.pretty_generate(data)
         
     | 
| 
      
 234 
     | 
    
         
            +
             
     | 
| 
      
 235 
     | 
    
         
            +
                      when :user? # true or false
         
     | 
| 
      
 236 
     | 
    
         
            +
                        obj
         
     | 
| 
      
 237 
     | 
    
         
            +
             
     | 
| 
      
 238 
     | 
    
         
            +
                      when :friendship? # true or false
         
     | 
| 
      
 239 
     | 
    
         
            +
                        obj
         
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
                      else
         
     | 
| 
      
 242 
     | 
    
         
            +
                        raise "#{__method__}: caller=#{caller_name} key=#{options[:key]} obj=#{obj.inspect}"
         
     | 
| 
      
 243 
     | 
    
         
            +
                    end
         
     | 
| 
      
 244 
     | 
    
         
            +
                  result
         
     | 
| 
      
 245 
     | 
    
         
            +
                end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
                # decode
         
     | 
| 
      
 248 
     | 
    
         
            +
                def decode_json(json_str, caller_name, options = {})
         
     | 
| 
      
 249 
     | 
    
         
            +
                  obj = json_str.kind_of?(String) ? JSON.parse(json_str) : json_str
         
     | 
| 
      
 250 
     | 
    
         
            +
                  result =
         
     | 
| 
      
 251 
     | 
    
         
            +
                    case
         
     | 
| 
      
 252 
     | 
    
         
            +
                      when obj.nil?
         
     | 
| 
      
 253 
     | 
    
         
            +
                        obj
         
     | 
| 
      
 254 
     | 
    
         
            +
             
     | 
| 
      
 255 
     | 
    
         
            +
                      when obj.kind_of?(Array) && obj.first.kind_of?(Hash)
         
     | 
| 
      
 256 
     | 
    
         
            +
                        obj.map { |o| Hashie::Mash.new(o) }
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
                      when obj.kind_of?(Array) && obj.first.kind_of?(Integer)
         
     | 
| 
      
 259 
     | 
    
         
            +
                        obj
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
                      when obj.kind_of?(Hash)
         
     | 
| 
      
 262 
     | 
    
         
            +
                        Hashie::Mash.new(obj)
         
     | 
| 
      
 263 
     | 
    
         
            +
             
     | 
| 
      
 264 
     | 
    
         
            +
                      when obj === true || obj === false
         
     | 
| 
      
 265 
     | 
    
         
            +
                        obj
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
                      when obj.kind_of?(Array) && obj.empty?
         
     | 
| 
      
 268 
     | 
    
         
            +
                        obj
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
                      else
         
     | 
| 
      
 271 
     | 
    
         
            +
                        raise "#{__method__}: caller=#{caller_name} key=#{options[:key]} obj=#{obj.inspect}"
         
     | 
| 
      
 272 
     | 
    
         
            +
                    end
         
     | 
| 
      
 273 
     | 
    
         
            +
                  result
         
     | 
| 
      
 274 
     | 
    
         
            +
                end
         
     | 
| 
      
 275 
     | 
    
         
            +
             
     | 
| 
      
 276 
     | 
    
         
            +
                def fetch_cache_or_call_api(method_name, user, options = {})
         
     | 
| 
      
 277 
     | 
    
         
            +
                  key = namespaced_key(method_name, user, options)
         
     | 
| 
      
 278 
     | 
    
         
            +
                  options.update(key: key)
         
     | 
| 
      
 279 
     | 
    
         
            +
             
     | 
| 
      
 280 
     | 
    
         
            +
                  data =
         
     | 
| 
      
 281 
     | 
    
         
            +
                    if options[:cache] == :read
         
     | 
| 
      
 282 
     | 
    
         
            +
                      instrument('Cache Read(Force)', key, caller: method_name) { cache.read(key) }
         
     | 
| 
      
 283 
     | 
    
         
            +
                    else
         
     | 
| 
      
 284 
     | 
    
         
            +
                      cache.fetch(key, expires_in: 1.hour, race_condition_ttl: 5.minutes) do
         
     | 
| 
      
 285 
     | 
    
         
            +
                        _d = yield
         
     | 
| 
      
 286 
     | 
    
         
            +
                        instrument('serialize', key, caller: method_name) { encode_json(_d, method_name, options) }
         
     | 
| 
      
 287 
     | 
    
         
            +
                      end
         
     | 
| 
      
 288 
     | 
    
         
            +
                    end
         
     | 
| 
      
 289 
     | 
    
         
            +
             
     | 
| 
      
 290 
     | 
    
         
            +
                  instrument('deserialize', key, caller: method_name) { decode_json(data, method_name, options) }
         
     | 
| 
      
 291 
     | 
    
         
            +
                end
         
     | 
| 
      
 292 
     | 
    
         
            +
              end
         
     | 
| 
      
 293 
     | 
    
         
            +
            end
         
     |