9fe77a0217c77ce4cb00096d863c8b45

This is a ruby gem I'm working on that wraps the highcharts javascript library.

1st Concern: I'm trying to provide a ruby API on top of the lib above, this is part of a larger object. I have to take this object into a hash( see #attrs ), so I can do .to_json upper in the build pipeline. I thought about just working with a hash directly underneath, but I talked out of that by a fellow ruby programmer.

I wonder if there's a better way to do this. Any thoughts?

1st Problem: As you can see there's a lot of duplication going on, but the #attrs method depends directly on
which attributes the current object has to build up a hash out of it, so it can be turned into a json, as mentioned above.

Is there a way to improve this? I could see creating modules for those identical groups, but how would attrs work on those attributes provided by the module?

module Highcharts
  module Option
    class Title

      attr_accessor :x,:y, :style, :margin, :text, :floating

      def align=(align)
        if !::Highcharts::ALIGNMENT.has_key? align
          raise UnsupportedAlignmentError, 'Alignment not supported'
        end
        @align = align
      end

      def vertical_align=(align)
        if !::Highcharts::ALIGNMENT.has_key? align
          raise UnsupportedAlignmentError, 'Alignment not supported'
        end
        @vertical_align = align
      end

      def attrs
        ({}.extend DeepMerge).tap do |me|
          me.deep_merge :title => {:align => @align} unless @align.nil?
          me.deep_merge :title => {:verticalAlign => @vertical_align} unless @vertical_align.nil?
          me.deep_merge :title => {:x => @x} unless @x.nil?
          me.deep_merge :title => {:y => @y} unless @y.nil?
          me.deep_merge :title => {:text => @text} unless @text.nil?
          me.deep_merge :title => {:margin => @margin} unless @margin.nil?
          me.deep_merge :title => {:style => @style} unless @style.nil?
        end
      end
    end
  end
end


# Duplication on x,y and alignments
module Highcharts
  module Option
    class Position

      attr_accessor :x, :y
      attr_reader :align, :vertical_align

      def align=(align)
        if !::Highcharts::ALIGNMENT.has_key? align
          raise UnsupportedAlignmentError, 'Alignment not supported'
        end
        @align = align
      end

      def vertical_align=(align)
        if !::Highcharts::ALIGNMENT.has_key? align
          raise UnsupportedAlignmentError, 'Alignment not supported'
        end
        @vertical_align = align
      end

      def attrs
        ({}.extend DeepMerge).tap do |me|
          me.deep_merge :position => {:align => @align} unless @align.nil?
          me.deep_merge :position => {:verticalAlign => @vertical_align} unless @vertical_align.nil?
          me.deep_merge :position => {:x => @x} unless @x.nil?
          me.deep_merge :position => {:y => @y} unless @y.nil?
        end
      end

    end
  end
end

Refactorings

No refactoring yet !

A74c34f1043b833b1fcc86ce9f3521ee

pahanix

November 30, 2010, November 30, 2010 01:29, permalink

No rating. Login to rate!
module Highcharts
  module Option
    class AlignmentStruct < Struct
      
      # we should override ::new not #initialize
      def self.new(*args)
        super(:align, :vertical_align, *args)
      end
      
      def align=(align)
        raise_on_unsupported_alignment(align)
        self[:align] = align
      end

      def vertical_align=(align)
        raise_on_unsupported_alignment(align)
        self[:vertical_align] = align
      end

      def attrs
        # Do you really need to extend Hash with DeepMerge here?
        attributes = {}
        each_pair{|member, value| attributes[member] = value if value}
        { current_object_symbol => attributes }
      end
        
      private
      
      # Transforms Highcharts::Option::Title into :title
      def current_object_symbol
        self.class.to_s.split('::').last.downcase.to_sym
      end
      
      def raise_on_unsupported_alignment(align)
        if !::Highcharts::ALIGNMENT.has_key? align
          raise UnsupportedAlignmentError, 'Alignment not supported'
        end
      end
    end

    Title = AlignmentStruct.new(:x,:y, :style, :margin, :text, :floating)
    Position = AlignmentStruct.new(:x,:y)
  end
end
A74c34f1043b833b1fcc86ce9f3521ee

pahanix

November 30, 2010, November 30, 2010 11:16, permalink

No rating. Login to rate!

Also you should transform :vertical_align into :verticalAlignin in your code

def attrs
  attributes = {}
  each_pair{|member, value| attributes[member] = value unless value.nil? }
  attributes.empty? ? {} : { current_object_symbol => attributes }
end

Your refactoring





Format Copy from initial code

or Cancel