From bc638ccb19d82cda0a2a8d734d4ba0259b287cbe Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 18 Feb 2015 13:11:25 +0100 Subject: [PATCH] v3: refactor model rendering --- lib/travis/api/v3/renderer.rb | 13 ---- lib/travis/api/v3/renderer/model_renderer.rb | 65 ++++++++++++++++++++ lib/travis/api/v3/renderer/organization.rb | 20 ++---- lib/travis/api/v3/renderer/repository.rb | 52 ++++++++-------- 4 files changed, 95 insertions(+), 55 deletions(-) create mode 100644 lib/travis/api/v3/renderer/model_renderer.rb diff --git a/lib/travis/api/v3/renderer.rb b/lib/travis/api/v3/renderer.rb index cb144413..d4fb7735 100644 --- a/lib/travis/api/v3/renderer.rb +++ b/lib/travis/api/v3/renderer.rb @@ -6,19 +6,6 @@ module Travis::API::V3 extend ConstantResolver extend self - def format_date(date) - date && date.strftime('%Y-%m-%dT%H:%M:%SZ') - end - - def get_attributes(object, *attributes, **defaults) - attributes.map { |a| [a, get_attribute(object, a, **defaults)] }.to_h - end - - def get_attribute(object, attribute, **defaults) - value = object.public_send(attribute) - value.nil? ? defaults[attribute] : value - end - def clear(**args) args.select { |key, value| !value.nil? } end diff --git a/lib/travis/api/v3/renderer/model_renderer.rb b/lib/travis/api/v3/renderer/model_renderer.rb new file mode 100644 index 00000000..0c508172 --- /dev/null +++ b/lib/travis/api/v3/renderer/model_renderer.rb @@ -0,0 +1,65 @@ +module Travis::API::V3 + class Renderer::ModelRenderer + PRIMITIVE = [String, Symbol, Numeric, true, false, nil] + private_constant :PRIMITIVE + + def self.type(type = nil) + @type = type if type + @type = name[/[^:]+$/].underscore.to_sym unless defined? @type # allows setting type to nil + @type + end + + def self.representation(name, *fields) + fields.each { |field| class_eval "def #{field}; @model.#{field}; end" unless method_defined?(field) } + representations[name] = fields + end + + def self.representations + @representations ||= {} + end + + def self.render(model, representation = :standard, **options) + new(model, **options).render(representation) + end + + attr_reader :model, :options, :script_name + attr_writer :href + + def initialize(model, script_name: nil, **options) + @model = model + @options = options + @script_name = script_name + end + + def href + return @href if defined? @href # allows setting href to nil + return unless self.class.type and model.respond_to? :id and model.id + @href = Renderer.href(self.class.type, script_name: script_name, id: model.id) + end + + def render(representation) + result = {} + result[:@type] = self.class.type if self.class.type + result[:@href] = href if href + fields = self.class.representations.fetch(representation) + + fields.each { |field| result[field] = render_value(send(field)) } + result + end + + def render_model(model, type: model.class.name.to_sym, mode: :minimal, **options) + Renderer[type].render(model, mode, script_name: script_name, **options) + end + + def render_value(value) + case value + when Hash then value.map { |k, v| [k, render_value(v)] }.to_h + when Array then value.map { |v | render_value(v) } + when *PRIMITIVE then value + when Time then value.strftime('%Y-%m-%dT%H:%M:%SZ') + when Travis::Model then render_model(value) + else raise ArgumentError, 'cannot render %p (%p)' % [value.class, value] + end + end + end +end diff --git a/lib/travis/api/v3/renderer/organization.rb b/lib/travis/api/v3/renderer/organization.rb index 33c0886a..1916151c 100644 --- a/lib/travis/api/v3/renderer/organization.rb +++ b/lib/travis/api/v3/renderer/organization.rb @@ -1,18 +1,8 @@ +require 'travis/api/v3/renderer/model_renderer' + module Travis::API::V3 - module Renderer::Organization - DIRECT_ATTRIBUTES = %i[id login name github_id] - extend self - - def render(organization, script_name: nil, **) - { - :@type => 'organization'.freeze, - :@href => Renderer.href(:organization, id: organization.id, script_name: script_name), - **direct_attributes(organization) - } - end - - def direct_attributes(repository) - DIRECT_ATTRIBUTES.map { |a| [a, repository.public_send(a)] }.to_h - end + class Renderer::Organization < Renderer::ModelRenderer + representation(:minimal, :id, :login) + representation(:standard, :id, :login, :name, :github_id) end end diff --git a/lib/travis/api/v3/renderer/repository.rb b/lib/travis/api/v3/renderer/repository.rb index 010f7b08..1eb7ef3a 100644 --- a/lib/travis/api/v3/renderer/repository.rb +++ b/lib/travis/api/v3/renderer/repository.rb @@ -1,38 +1,36 @@ +require 'travis/api/v3/renderer/model_renderer' + module Travis::API::V3 - module Renderer::Repository - DIRECT_ATTRIBUTES = %i[id name slug description github_language private active default_branch] - DEFAULTS = { active: false, default_branch: 'master' } - extend self + class Renderer::Repository < Renderer::ModelRenderer + representation(:minimal, :id, :slug) + representation(:standard, :id, :name, :slug, :description, :github_language, :active, :private, :default_branch, :owner, :last_build) - def render(repository, script_name: nil, **) + def default_branch + model.default_branch || 'master'.freeze + end + + def active + !!model.active + end + + def owner { - :@type => 'repository'.freeze, - :@href => Renderer.href(:repository, id: repository.id, script_name: script_name), - **Renderer.get_attributes(repository, *DIRECT_ATTRIBUTES, **DEFAULTS), **nested_resources(repository) + :@type => model.owner_type && model.owner_type.downcase, + :id => model.owner_id, + :login => model.owner_name } end - def nested_resources(repository) - { - owner: { - :@type => repository.owner_type && repository.owner_type.downcase, - :id => repository.owner_id, - :login => repository.owner_name - }, - last_build: last_build(repository) - } - end - - def last_build(repository) - return nil unless repository.last_build_id + def last_build + return nil unless model.last_build_id { :@type => 'build'.freeze, - :id => repository.last_build_id, - :number => repository.last_build_number, - :state => repository.last_build_state.to_s, - :duration => repository.last_build_duration, - :started_at => Renderer.format_date(repository.last_build_started_at), - :finished_at => Renderer.format_date(repository.last_build_finished_at), + :id => model.last_build_id, + :number => model.last_build_number, + :state => model.last_build_state.to_s, + :duration => model.last_build_duration, + :started_at => model.last_build_started_at, + :finished_at => model.last_build_finished_at, } end end