%%% STEP 8: added double support

% classdef MyFraction < handle
%     properties (SetAccess = private)
%         nominator = []
%         denominator = []
%     end
%     methods
%         function obj = MyFraction(nom, denom)
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             if nargin == 1
%                 obj.setNominator(nom);
%                 obj.setDenominator(1);
%             else
%                 obj.setNominator(nom);
%                 obj.setDenominator(denom);
%             end
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         end
%         function setNominator(obj, nominator)
%             obj.nominator = nominator;
%             obj.reduce()
%         end
%         function setDenominator(obj, denom)
%             if denom == 0 
%                 error('Denominator must not be equal to zero.')
%             end
%             obj.denominator = denom;
%             obj.reduce()
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%         function disp(obj)
%             fprintf('   %d/%d\n\n', obj.nominator, obj.denominator)
%         end
%         function out = plus(obj,obj2)
%             if isnumeric(obj)
%                 out = MyFraction(obj*obj2.denominator+obj2.nominator,obj2.denominator);
%             elseif isnumeric(obj2)
%                 out = MyFraction(obj2*obj.denominator+obj.nominator,obj.denominator);
%             elseif isa(obj, 'MyFraction') && isa(obj2, 'MyFraction')
%                 out = MyFraction(obj.nominator*obj2.denominator+obj2.nominator*obj.denominator, ...
%                 obj.denominator*obj2.denominator);
%             else
%                 error('Cannot add %s to %s.', class(obj), class(obj2))
%             end
%         end
%         function out = uminus(obj)
%             out = MyFraction(-obj.nominator, obj.denominator);
%         end
%         function out = minus(obj,obj2)
%             if isnumeric(obj)
%                 out = MyFraction(obj*obj2.denominator-obj2.nominator,obj2.denominator);
%             else
%                 out = obj.plus(-obj2);
%             end
%         end
%     end
%     methods (Hidden = true)
%         function reduce(obj)
%             if isempty(obj.nominator) || isempty(obj.denominator)
%                 return
%             end
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             % this method is simple but not necessarily efficient
%             if mod(obj.nominator,1) ~=0 || mod(obj.denominator,1) ~=0
%                 counter = 1;
%                 while mod(obj.nominator*10^counter,1) ~=0 || mod(obj.denominator*10^counter,1) ~=0
%                     counter = counter + 1;
%                 end
%                 obj.nominator = obj.nominator*10^counter;
%                 obj.denominator = obj.denominator*10^counter;
%             end
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             isnegative = obj.nominator*obj.denominator < 0;
%             mygcd = gcd(abs(obj.nominator), abs(obj.denominator));
%             obj.nominator = abs(obj.nominator)/mygcd;
%             obj.denominator = abs(obj.denominator)/mygcd;
%             if isnegative
%                 obj.nominator = -obj.nominator;
%             end
%         end
%     end
% end

%%% STEP 7: making operators work with integers

% classdef MyFraction < handle
%     properties (SetAccess = private)
%         nominator = []
%         denominator = []
%     end
%     methods
%         function obj = MyFraction(nom, denom)
%             obj.setNominator(nom);
%             obj.setDenominator(denom);
%         end
%         function setNominator(obj, nominator)
%             if mod(nominator,1) ~=0
%                 error('Nominator must be an integer.')
%             end
%             obj.nominator = nominator;
%             obj.reduce()
%         end
%         function setDenominator(obj, denom)
%             if denom == 0 || mod(denom,1) ~=0
%                 error('Denominator must be an integer and not equal to zero.')
%             end
%             obj.denominator = denom;
%             obj.reduce()
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%         function disp(obj)
%             fprintf('   %d/%d\n\n', obj.nominator, obj.denominator)
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function out = plus(obj,obj2)
%             if isnumeric(obj)
%                 out = MyFraction(obj*obj2.denominator+obj2.nominator,obj2.denominator);
%             elseif isnumeric(obj2)
%                 out = MyFraction(obj2*obj.denominator+obj.nominator,obj.denominator);
%             elseif isa(obj, 'MyFraction') && isa(obj2, 'MyFraction')
%                 out = MyFraction(obj.nominator*obj2.denominator+obj2.nominator*obj.denominator, ...
%                 obj.denominator*obj2.denominator);
%             else
%                 error('Cannot add %s to %s.', class(obj), class(obj2))
%             end
%         end
%         function out = uminus(obj)
%             out = MyFraction(-obj.nominator, obj.denominator);
%         end
%         function out = minus(obj,obj2)
%             if isnumeric(obj)
%                 out = MyFraction(obj*obj2.denominator-obj2.nominator,obj2.denominator);
%             else
%                 out = obj.plus(-obj2);
%             end
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     end
%     methods (Hidden = true)
%         function reduce(obj)
%             if isempty(obj.nominator) || isempty(obj.denominator)
%                 return
%             end
%             isnegative = obj.nominator*obj.denominator < 0;
%             mygcd = gcd(abs(obj.nominator), abs(obj.denominator));
%             obj.nominator = abs(obj.nominator)/mygcd;
%             obj.denominator = abs(obj.denominator)/mygcd;
%             if isnegative
%                 obj.nominator = -obj.nominator;
%             end
%         end
%     end
% end

%%% STEP 6: overloading operators

% classdef MyFraction < handle
%     properties (SetAccess = private)
%         nominator = []
%         denominator = []
%     end
%     methods
%         function obj = MyFraction(nom, denom)
%             obj.setNominator(nom);
%             obj.setDenominator(denom);
%         end
%         function setNominator(obj, nominator)
%             if mod(nominator,1) ~=0
%                 error('Nominator must be an integer.')
%             end
%             obj.nominator = nominator;
%             obj.reduce()
%         end
%         function setDenominator(obj, denom)
%             if denom == 0 || mod(denom,1) ~=0
%                 error('Denominator must be an integer and not equal to zero.')
%             end
%             obj.denominator = denom;
%             obj.reduce()
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%         function disp(obj)
%             fprintf('   %d/%d\n\n', obj.nominator, obj.denominator)
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function out = plus(obj,obj2)
%             out = MyFraction(obj.nominator*obj2.denominator+obj2.nominator*obj.denominator, ...
%                 obj.denominator*obj2.denominator);
%         end
%         function out = uminus(obj)
%             out = MyFraction(-obj.nominator, obj.denominator);
%         end
%         function out = minus(obj,obj2)
%             out = obj.plus(-obj2);
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     end
%     methods (Hidden = true)
%         function reduce(obj)
%             if isempty(obj.nominator) || isempty(obj.denominator)
%                 return
%             end
%             isnegative = obj.nominator*obj.denominator < 0;
%             mygcd = gcd(abs(obj.nominator), abs(obj.denominator));
%             obj.nominator = abs(obj.nominator)/mygcd;
%             obj.denominator = abs(obj.denominator)/mygcd;
%             if isnegative
%                 obj.nominator = -obj.nominator;
%             end
%         end
%     end
% end

%%% STEP 5: disp function

% classdef MyFraction < handle
%     properties (SetAccess = private)
%         nominator = []
%         denominator = []
%     end
%     methods
%         function obj = MyFraction(nom, denom)
%             obj.setNominator(nom);
%             obj.setDenominator(denom);
%         end
%         function setNominator(obj, nominator)
%             if mod(nominator,1) ~=0
%                 error('Nominator must be an integer.')
%             end
%             obj.nominator = nominator;
%             obj.reduce()
%         end
%         function setDenominator(obj, denom)
%             if denom == 0 || mod(denom,1) ~=0
%                 error('Denominator must be an integer and not equal to zero.')
%             end
%             obj.denominator = denom;
%             obj.reduce()
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function disp(obj)
%             fprintf('   %d/%d\n\n', obj.nominator, obj.denominator)
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     end
%     methods (Hidden = true)
%         function reduce(obj)
%             if isempty(obj.nominator) || isempty(obj.denominator)
%                 return
%             end
%             isnegative = obj.nominator*obj.denominator < 0;
%             mygcd = gcd(abs(obj.nominator), abs(obj.denominator));
%             obj.nominator = abs(obj.nominator)/mygcd;
%             obj.denominator = abs(obj.denominator)/mygcd;
%             if isnegative
%                 obj.nominator = -obj.nominator;
%             end
%         end
%     end
% end

%%% STEP 4: hidden functions / reduce

% classdef MyFraction < handle
%     properties (SetAccess = private)
%         nominator = []
%         denominator = []
%     end
%     methods
%         function obj = MyFraction(nom, denom)
%             obj.setNominator(nom);
%             obj.setDenominator(denom);
%         end
%         function setNominator(obj, nominator)
%             if mod(nominator,1) ~=0
%                 error('Nominator must be an integer.')
%             end
%             obj.nominator = nominator;
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             obj.reduce()
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         end
%         function setDenominator(obj, denom)
%             if denom == 0 || mod(denom,1) ~=0
%                 error('Denominator must be an integer and not equal to zero.')
%             end
%             obj.denominator = denom;
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             obj.reduce()
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%     end
%     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     methods (Hidden = true)
%         function reduce(obj)
%             if isempty(obj.nominator) || isempty(obj.denominator)
%                 return
%             end
%             isnegative = obj.nominator*obj.denominator < 0;
%             mygcd = gcd(abs(obj.nominator), abs(obj.denominator));
%             obj.nominator = abs(obj.nominator)/mygcd;
%             obj.denominator = abs(obj.denominator)/mygcd;
%             if isnegative
%                 obj.nominator = -obj.nominator;
%             end
%         end
%     end
%     %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% end

%%% STEP 3: limiting access, checks

% classdef MyFraction < handle
%     properties (SetAccess = private) %%%%%%
%         nominator = []
%         denominator = []
%     end
%     methods
%         function obj = MyFraction(nom, denom)
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             obj.setNominator(nom);
%             obj.setDenominator(denom);
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         end
%         function setNominator(obj, nominator)
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             % this does not check for strings or other input
%             if mod(nominator,1) ~=0
%                 error('Nominator must be an integer.')
%             end
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             obj.nominator = nominator;
%         end
%         function setDenominator(obj, denom)
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             if denom == 0 || mod(denom,1) ~=0
%                 error('Denominator must be an integer and not equal to zero.')
%             end
%             %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%             obj.denominator = denom;
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%     end
% end

%%% STEP 2: constructor

% classdef MyFraction < handle
%     properties
%         nominator = []
%         denominator = []
%     end
%     methods
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function obj = MyFraction(nom, denom)
%             obj.nominator = nom;
%             obj.denominator = denom;
%         end
%         %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%         function setNominator(obj, nominator)
%             obj.nominator = nominator;
%         end
%         function setDenominator(obj, denom)
%             obj.denominator = denom;
%         end
%         function out = toDouble(obj)
%             out = obj.nominator/obj.denominator;
%         end
%     end
% end

%%% STEP 1: basic layout

classdef MyFraction < handle
    properties
        nominator = []
        denominator = []
    end
    methods
        function setNominator(obj, nominator)
            obj.nominator = nominator;
        end
        function setDenominator(obj, denom)
            obj.denominator = denom;
        end
        function out = toDouble(obj)
            out = obj.nominator/obj.denominator;
        end
    end
end

