Author: Sherry

chic classy developer (;

AngularJS, Pact, and Jasmine

  1. Follow the steps in pact-consumer-js-dsl (yes, with the gem ‘pact-mock_service’)
  2. Here is where the important stuff comes with AngularJS:

given service:

angular.module('ng-cherie.services.current-theme', [
    'ng-cherie.constants'
])
    .factory('currentThemeService', function currentThemeService($http, API) {
        var service = {
            getCurrentTheme: getCurrentTheme
        };

        function getCurrentTheme() {
            var theme;
            return $http.get(API.BASE_PATH + API.CURRENT_THEME)
                .then(function getCurrentThemeSuccess(response) {
                    theme = response.data;

                    return theme;
                }, function() {
                    return null;
                });
        }

        return service;
    });

then pact with ngMidwayTester

/* globals ngMidwayTester */ 
/* globals Pact */
describe('currentThemeService', function() {
    var API,
        currentThemeProvider,
        currentThemeService,
        mockCurrentTheme,
        $httpBackend,
        tester;

    beforeEach(function() {
        angular.module('currentThemeServiceSpec', [
          'ng-cherie.services.current-theme',
          'ng-cherie.constants',
          'ng-cherie.mocks.current-theme',
          'ngMockE2E'
        ]);

        tester = ngMidwayTester('currentThemeServiceSpec');
        currentThemeService = tester.inject('currentThemeService');
        API = tester.inject('API');
        mockCurrentTheme = tester.inject('mockCurrentTheme');

        $httpBackend = tester.inject('$httpBackend');
        $httpBackend.whenGET(/\/api\/v1\/currenttheme/).passThrough();

        currentThemeProvider = Pact.mockService({
            consumer: 'ng-cherie.services.current-theme',
            provider: 'CherieApp',
            port: 1234,
            done: function (error) {
                expect(error).toBe(null);
            }
        });
    });

    afterEach(function () {
        tester.destroy();
        tester = null;
    });

    describe('getCurrentTheme', function() {
       it('should return the current theme via pact', function(done) {

           API.BASE_PATH = "http://localhost:1234" + API.BASE_PATH;

           currentThemeProvider
               .uponReceiving("a request for the current theme")
               .withRequest("get", "/api/v1/currenttheme")
               .willRespondWith(200, { "Content-Type": "application/json" }, mockCurrentTheme);

           currentThemeProvider.run(done, function(runComplete) {
               currentThemeService.getCurrentTheme().then(function(response) {
                   expect(response).toEqual(mockCurrentTheme);
                   runComplete();
               });
           });
       });
    });

});

line 12: the key is to set up a new module that contains ngMockE2E so we can use `passthrough`
line 45: make sure to replace the domain with the pact server location, in this case, it is localhost:1234.

Advertisements

AngularJS compile vs templateUrl

Hello, hello, it has been a while since my last post of ‘given, then, show’. If you are new to here, this is not a recommendation on how to implement, but rather just a show and tell of what you can do.

Given:

– Implement a directive that handles these providers:
– Provider A, B, C, and D share the same template
– Provider A and B have different description
– Provider C and D have no description
– Provider E and F have different templates and different description

Then:

– Assuming that templates and provider descriptions are dumb aka not stored in controllers
– Implement a directive that shows the default template, which is share across the similar providers (A, B, C, D) and a separate template per unique provider E and F.
– Implement a directive just for passing in unique descriptions

————————————>>>>>>————————————
Call the directive

<demo provider="provider"></demo>

Method 1a: use compiler


angular.module('ng-cherie.directives.demo.directive', [])
    .directive('demo', function demoDirective($compile, $templateCache) {
        return {
            bindToController: true,
            controller: 'DemoCtrl as demoCtrl',
            link: function demoLink(scope, elem, attrs, demoCtrl) {
                var defaultTemplatePath = 'app/directives/demo/templates/default.tpl.html',
                    templatePath = defaultTemplatePath.replace(/default/, demoCtrl.provider.id),
                    template;

                template = $templateCache.get(templatePath) || $templateCache.get(defaultTemplatePath);
                $compile(elem.html(template).contents())(scope);
            },
            scope: {
                provider: '='
            }
        };
    });

Method 1b: use compiler

angular.module('ng-cherie.directives.demo.directive', [])
    .directive('demo', function demoDirective($compile, $templateCache) {
        return {
            bindToController: true,
            controller: 'DemoCtrl as demoCtrl',
            link: function demoLink(scope, elem, attrs, demoCtrl) {
                var defaultTemplatePath = 'app/directives/demo/templates/default.tpl.html',
                    templatePath = defaultTemplatePath.replace(/default/, demoCtrl.provider.id),
                    template;

                template = $templateCache.get(templatePath) || $templateCache.get(defaultTemplatePath);
                elem.append($compile(template)(scope));
            },
            scope: {
                provider: '='
            }
        };
    });

Method 2: use ng-include

angular.module('ng-cherie.directives.demo.directive', [])
    .directive('demo', function demoDirective() {
        return {
            bindToController: true,
            controller: 'DemoCtrl as demoCtrl',
            scope: {
                provider: '='
            },
            templateUrl: 'app/directives/demo/templates/demo.tpl.html'
        };
    });

where app/directives/demo/templates/demo.tpl.html is

<ng-include src="demoCtrl.showTemplate()"></ng-include>

where showTemplate() determines which template to show depending on the provider (similar to demoLink())

————————————>>>>>>————————————
in default.tpl.html:
use a directive (demoDescription directive) to pass in the description and a control to show the description, so that when demo directive (see above) renders the default template directly without the description, it won’t fail on missing transclusion.

<p class="demo-description" ng-transclude ng-if="demoDescriptionCtrl.isTemplateUsedWithDirective"></p>

call the directive:

<demo-description>
    {{ 'Provider description here.' | translate }}
</demo-description>

————————————>>>>>>————————————
jasmine test

describe('Demo directive', function() {
    var _,
        $compile,
        element,
        providerMockData,
        scope;

    beforeEach(module('ng-cherie.directives.demo'));
    beforeEach(module('ng-cherie.mocks.provider'));

    beforeEach(inject(function($injector) {
        _ = $injector.get('_');
        $compile = $injector.get('$compile');
        scope = $injector.get('$rootScope').$new();
        providerMockData = $injector.get('providerMockData');
    }));

    beforeEach(function() {
        scope.provider = _.first(providerMockData.providers);
    });

    function compileDirective(scope) {
        var compiledElement = $compile('<demo provider="provider"></demo>')(scope);

        scope.$digest();

        return compiledElement;
    }

    describe('compiled markup', function() {
        it('contains the expected markup', function() {
            element = compileDirective(scope);

            expect(element[0].querySelector('.demo-body')).not.toBeNull();
        });

        //some other tests here... mostly expecting certain classes to be or not be there

        it('shows the default template when the provider is unknown', function () {
            scope.provider.id = "unexpected_provider";
            element = compileDirective(scope);

            expect(element.find('demo-description').length).toBe(0);
        });
    });
});

compressor function

given: “aaabbcca”
return: “a3b2c2a1”

def compressor(string)
	# initialize
	compressed = ''
	count = 0
	i = 0

	size = string.size

	string.each_char do |s|
		
		i += 1

		if compressed[-1].nil?
			count = 1
			compressed = s
			next
		end

		# when c[-1] = a, s = a
		if compressed[-1] == s 
			count += 1
			# last character
			if i == size
				compressed << count.to_s
			end
			next
		end

		# when c[-1] = a, s = b
		if compressed[-1] !=s
			compressed << count.to_s << s
			count = 1
			next
		end

	end
	compressed
end

angularjs rails simple_form name

when using rails simple_form and angularjs for form validation

= simple_form_for :address, url: account_path(account.id), 
                            method: :patch, wrapper: :custom,
                            defaults: { input_html: { required: true } },
                            html: { name: 'addressForm',
                                    novalidate: true,
                                    'ng-submit' => "addressCtrl.submitForm(addressForm, $event)" } do |f|

  %fieldset.form-fieldset
    = f.input :address_1, input_html: { name: 'contact[street_address_1]', 
                                        'ng-model' => 'addressCtrl.address.street_address_1', 
                                        'ng-init' => "addressCtrl.address.street_address_1='#{account.street_address_1}'" }, 
                          wrapper_html: { 'ng-class' => "{'form-field--error': addressForm['contact[street_address_1]'].$invalid && addressForm['contact[street_address_1]'].$touched}" },
                          error_wrapper_html: { 'translate' => 'address.error.required.street_address_1', 
                                                'ng-show' => "addressForm['contact[street_address_1]'].$error.required && addressForm['contact[street_address_1]'].$touched" }

...

given input name

  name: 'contact[street_address_1]'

angularjs calls it by:

  addressForm['contact[street_address_1]']

Find all prime numbers between x & y

I was watching this today… Learn Ruby Programming – Day 17 – Find Prime Numbers

well almost half way through before I decided to run it myself
note: it’s not an exact copy but the core is the same

def find_prime(x,y)
  prime = []
  while (x <= y)
    prime_flag = true
    i = 2
    while (i <= x/2)
      if x%i == 0 
        prime_flag = false
        break
      end
      i +=1
    end
    if prime_flag
      prime << x
    end
    x+=1
  end
  prime
end

and someone suggested to use #find

def prime_between(x,y)
  prime = []
  while x <= y
    result = (2..x).find{|i| x%i == 0}
    prime << x if result == x
    x +=1
  end
  prime
end

Yep #prime_between is definitely much neater than #find_prime, but how about the time?

t = Time.now
10.times{find_prime(7,100)}
puts "#find_prime: #{Time.now - t}"

t = Time.now
10.times{prime_between(7,100)}
puts "#prime_between: #{Time.now - t}"

#and in case you wanna see benchmark

require "benchmark"
time = Benchmark.measure do
  find_prime(7,100)
end
puts time

time1 = Benchmark.measure do
  prime_between(7,100)
end
puts time1

————- result

time 1: 0.000462
time 2: 0.001452
——————-
0.000000 0.000000 0.000000 ( 0.000052)
0.000000 0.000000 0.000000 ( 0.000167)

So even though #prime_between is neater, it’s slower… noted that #find_prime goes up to x/2

#...
while (i <= x/2)

whereas #prime_between goes up to x

#...
result = (2..x).find{|i| x%i == 0}

so in worst case scenario, #prime_between is obviously going to run longer…

so I updated #prime_between

def prime_between(x,y)
  prime = []
  while x <= y
    result = (2..x/2).find{|i| x%i == 0}
    prime << x if result.nil?
    x +=1
  end
  prime
end

updated benchmark:
#find_prime: 0.000463
#prime_between: 0.001015
——————-
0.000000 0.000000 0.000000 ( 0.000052)
0.000000 0.000000 0.000000 ( 0.000127)

Hmmm… yep a little faster than the previous #prime_between but still slower than #find_prime.

Anyway, here’s another one inspired by Sieve of Eratosthenes

def sieve_prime(x,y)
  prime = (x..y).to_a
  while (x<=y)
    (2..Math.sqrt(x)).each do |i|
      if x%i == 0
        prime -= [x]
        break
      end
    end
    x +=1
  end
  prime
end

ways to use #inject

sum an array

[0,1,2,3].inject(0){|sum, i| sum+i}
#=> 6

——————>>>>>>——————

linear array into hash

["apple", "orange", "pineapple"].inject({}){|k, v| k[v]=1; k} 
#=> {"apple"=>1, "orange"=>1, "pineapple"=>1} 

k: {}
v: apple
k: {“apple”=>1}
v: orange
k: {“apple”=>1, “orange”=>1}
v: pineapple
=> {“apple”=>1, “orange”=>1, “pineapple”=>1}

check this out

fruits = ["apple", "orange", "pineapple", "apple"]
fruits.inject(Hash.new(0)){|k, v| k[v]+=1; k} 
 #=> {"apple"=>2, "orange"=>1, "pineapple"=>1} 

or use #update

[0,1,2,3].inject({}) {|result, i| result.update(i => i+1)}
#=> {0=>1, 1=>2, 2=>3, 3=>4} 

k: {}
v: 0
k: {0=>1}
v: 1
k: {0=>1, 1=>2}
v: 2
k: {0=>1, 1=>2, 2=>3}
v: 3
=> {0=>1, 1=>2, 2=>3, 3=>4}

notice the difference in these two and the importance- make sure a hash is returned.

——————>>>>>>——————

arrays into hash

 def array_to_hash(array)
   array.inject({}) do |result, element|
     result[element.first] = element.last
     result
   end
 end

a = [[:fruit, "apple"],[:taste, "good"]]
array_to_hash(a)
#=> {:fruit=>"apple", :taste=>"good"} 

sidenote: or use Hash and group the arrays

Hash[*[[:fruit, "apple"],[:taste, "good"]].flatten]
#=> {:fruit=>"apple", :taste=>"good"} 

or this… dudh

[[:fruit, "apple"], [:taste, "good"]].to_h
#=> {:fruit=>"apple", :taste=>"good"} 

——————>>>>>>——————

turn hash into array

h = {0=>1, 1=>2, 2=>3, 3=>4}
h.inject([]){|result, i| p result; p i; result<<i}
#=> [[0, 1], [1, 2], [2, 3], [3, 4]] 

or this… dudh no.2

h.to_a
#=> [[0, 1], [1, 2], [2, 3], [3, 4]] 

——————>>>>>>——————

swap keys and values in hash

braces = {"[" => "]", "(" => ")", "{" => "}"}
braces.inject({}){|result, (k,v)| result[v]=k; result}
# => {"]"=>"[", ")"=>"(", "}"=>"{"} 

or invert

braces.invert
# => {"]"=>"[", ")"=>"(", "}"=>"{"} 

but both are lossy, if there’re multiple of the same values, then only the last value will be saved… this is where each_with_object comes in handy.

s = {:a=>1, :b=>2, :c=>2} 
s.each_with_object({}){|(k,v), result| result[v] ||=[]; result[v] << k }
# => {1=>[:a], 2=>[:b, :c]} 

these are only some basic usage, but hopefully you get the gist to use it to your advantages.