twitterdev/twitter-ruby-ads-sdk

View on GitHub
lib/twitter-ads/resources/dsl.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true
# Copyright (C) 2019 Twitter, Inc.

module TwitterAds
  # A light-wight DSL for building out Twitter Ads API resources.
  module DSL

    def self.included(klass)
      klass.send :include, InstanceMethods
      klass.extend ClassMethods
    end

    module InstanceMethods

      # Populates a given objects attributes from a parsed JSON API response. This helper
      # handles all necessary type coercions as it assigns attribute values.
      #
      # @param object [Hash] The parsed JSON response object.
      #
      # @return [self] A fully hydrated instance of the current class.
      #
      # @since 0.1.0
      def from_response(object, headers = nil)
        if !headers.nil?
          TwitterAds::Utils.extract_response_headers(headers).each { |key, value|
            singleton_class.class_eval { attr_accessor key }
            instance_variable_set("@#{key}", value)
          }
        end

        self.class.properties.each do |name, type|
          value = nil
          if type == :time && object[name] && !object[name].empty?
            value = Time.parse(object[name])
          elsif type == :bool && object[name]
            value = TwitterAds::Utils.to_bool(object[name])
          end
          instance_variable_set("@#{name}", value || object[name])
        end
        self
      end

      # Generates a Hash of property values for the current object. This helper
      # handles all necessary type coercions as it generates its output.
      #
      # @return [Hash] A Hash of the object's properties and cooresponding values.
      #
      # @since 0.1.0
      def to_params
        params = {}
        self.class.properties.each do |name, type|
          value = instance_variable_get("@#{name}") || send(name)
          next if value.nil?

          # handles unset with empty string
          if value.respond_to?(:strip) && value.strip == ''
            params[name] = value.strip
            next
          end

          if type == :time
            params[name] = value.iso8601
          elsif type == :bool
            params[name] = TwitterAds::Utils.to_bool(value)
          elsif value.is_a?(Array)
            next if value.empty?
            params[name] = value.join(',')
          else
            params[name] = value
          end
        end
        params
      end

    end

    module ClassMethods

      # Resource property declaration helper.
      #
      # @example
      #   class Foo
      #     include TwitterAds::DSL
      #
      #     property :foo
      #     property :bar, type: :bool
      #     property :created_at, type: time, read_only: true
      #   end
      #
      # @param name [Symbol] The name of the property.
      # @param opts [Hash] A Hash of extended options to be applied to the property (Optional).
      #
      # @return [Symbol] The property name.
      #
      # @since 0.1.0
      def property(name, opts = {})
        properties[name] = opts.fetch(:type, nil)
        opts[:read_only] ? attr_reader(name) : attr_accessor(name)
        name
      end

      # Helper for managing properties for the current class.
      #
      # @return [Hash] A Hash of properties declared in the current class.
      #
      # @api private
      # @since 0.1.0
      def properties
        @properties ||= {}
      end

    end

  end
end