$ cargo build
Compiling hello_world v0.1.0 (.../hello_world)
Finished dev [unoptimized + debuginfo] target(s) in 6.32s
Or build a production ready version
$ cargo build --release<br>Finished release [optimized] target(s) in 0.19s
Run your app
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.04s
Running `target/debug/hello_world
Hello, world!
Add functionality to your app
Add Dependencies
Let’s add a dependency to our application. You can find all sorts of libraries on crates.io, the package registry for Rust. In Rust, we often refer to packages as “crates.”
In this project, we’ll use a crate called ferris-says.
In our Cargo.toml file we’ll add this information (that we got from the crate page):
[dependencies]
ferris-says = "0.1"
Modify main source
Now let’s write a small application with our new dependency. In our main.rs, add the following code:
use ferris_says::say; // from the previous step
use std::io::{stdout, BufWriter};
fn main() {
let stdout = stdout();
let message = String::from("Hello fellow Rustaceans!");
let width = message.chars().count();
let mut writer = BufWriter::new(stdout.lock());
say(message.as_bytes(), width, &mut writer).unwrap();
}
Starten Sie die Datenbank in einem eigenen Fenster mit dem nachfolgenden Kommando:
docker compose up
[+] Running 14/14
- db Pulled
- b4d181a07f80 Already exists
- 46ca1d02c28c Pull complete
- a756866b5565 Pull complete
- 36c49e539e90 Pull complete
- 664019fbcaff Pull complete
- 727aeee9c480 Pull complete
- 796589e6b223 Pull complete
- 6664992e747d Pull complete
- 0f933aa7ccec Pull complete
- 99b5e5d88b32 Pull complete
- a901b82e6004 Pull complete
- 625fd35fd0f3 Pull complete
- 9e37bf358a5d Pull complete
[+] Running 1/1
- Container elixis_postgres Started
Attaching to elixis_postgres
elixis_postgres | The files belonging to this database system will be owned by user "postgres".
elixis_postgres | This user must also own the server process.
...
...
...
elixis_postgres | 2021-07-12 15:01:08.042 UTC [1] LOG: database system is ready to accept connections
Datenbanktabellen erstellen
Festlegen der Datenbank-Verbindungsparameter in der Datei config/dev.exs.
Wir verwenden dabie die gleichen Werte, die wir in der Datei docker-compose.yml verwendet haben:
cobc --version
cobc (GnuCOBOL) 2.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch, Edward Hart
Built Oct 15 2019 14:14:21
Packaged Sep 06 2017 18:48:43 UTC
C version "4.2.1 Compatible Apple LLVM 11.0.0 (clang-1100.0.33.8)"
First Steps
Create sample programm
Create Hello World programm hello_world.cob
HELLO * HISTORIC EXAMPLE OF HELLO WORLD IN COBOL
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "HELLO, WORLD".
STOP RUN.
Using Jenkins as an automation server for your development, you can automate such repeating tasks as testing and deploying your app.
Starting with a sample Groovy App (a simple calculator) with tests, you will learn how to integrate your app in Jenkins and build a pipeline, so that Jenkins runs the desired tasks every time, you change the code.
You should clone the demo repository into you demo account, because you may change some file during this post., and you will not get write permissions for the demo repository.
Also, clone the repository to your local machine to see what our demo app looks like.
$ cd SampleApp_GroovyCalculator/
$ ls
Jenkinsfile README.md bin build.gradle gradlew src
Makefile SampleCalculator build gradle settings.gradle
The first task, Jenkins will do in our pipeline: build your app
$ ./gradlew build
Because it’s the first time you start gradlew, the required software will be downloaded:
First: the current Gradle Version (Gradle is the Build Tool used by Groovy Projects)
Downloading https://services.gradle.org/distributions/gradle-6.2.1-bin.zip
………10%………20%………30%……….40%………50%………60%……….70%………80%………90%……….100%
Welcome to Gradle 6.2.1!
Here are the highlights of this release:
- Dependency checksum and signature verification
- Shareable read-only dependency cache
- Documentation links in deprecation messages
For more details see https://docs.gradle.org/6.2.1/release-notes.html
Starting a Gradle Daemon, 2 stopped Daemons could not be reused, use --status for details
After this, your app will be tested
> Task :test
Calculator02Spec > two plus two should equal four PASSED
Calculator01Spec > add: 2 + 3 PASSED
Calculator01Spec > subtract: 4 - 3 PASSED
Calculator01Spec > multiply: 2 * 3 PASSED
BUILD SUCCESSFUL in 34s
5 actionable tasks: 5 executed
Perform the build again
No download is required. The build is much quicker.
$ az webapp up --sku F1 -n azure-toolbox-flask-demo -l westeurope
webapp azure-toolbox-flask-demo doesn't exist
Creating Resource group 'xx_xx_Linux_westeurope' ...
Resource group creation complete
Creating AppServicePlan 'xx_asp_Linux_westeurope_0' ...
Creating webapp 'flask-demo' ...
Configuring default logging for the app, if not already enabled
Creating zip with contents of dir .../Working-with_Python ...
Getting scm site credentials for zip deployment
Starting zip deployment. This operation can take a while to complete ...
Deployment endpoint responded with status code 202
You can launch the app at http://via-internet-flask-demo.azurewebsites.net
{
"URL": "http:/azure-toolbox-flask-demo.azurewebsites.net",
"appserviceplan": "xx_asp_Linux_westeurope_0",
"location": "westeurope",
"name": "azure-toolbox--flask-demo",
"os": "Linux",
"resourcegroup": "xx_xx_Linux_westeurope",
"runtime_version": "python|3.7",
"runtime_version_detected": "-",
"sku": "FREE",
"src_path": ".../Working-with_Python"
}
Create Django App with PostgreSQL
Installation PostgreSQL on Mac OS
$ brew install postgres
==> Installing dependencies for postgresql: krb5
==> Installing postgresql dependency: krb5
...
==> Installing postgresql
...
==> Caveats
==> krb5
krb5 is keg-only, which means it was not symlinked into /usr/local, because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.
If you need to have krb5 first in your PATH run:
echo 'export PATH="/usr/local/opt/krb5/bin:$PATH"' >> ~/.bash_profile
echo 'export PATH="/usr/local/opt/krb5/sbin:$PATH"' >> ~/.bash_profile
For compilers to find krb5 you may need to set:
export LDFLAGS="-L/usr/local/opt/krb5/lib"
export CPPFLAGS="-I/usr/local/opt/krb5/include"
For pkg-config to find krb5 you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/krb5/lib/pkgconfig"
==> postgresql
To migrate existing data from a previous major version of PostgreSQL run:
brew postgresql-upgrade-database
To have launchd start postgresql now and restart at login:
brew services start postgresql
Or, if you don't want/need a background service you can just run:
pg_ctl -D /usr/local/var/postgres start
Set user and passwords for postgres database
Create database and user for django app
$ psql postgres
psql (12.1)
Type "help" for help.
postgres=# CREATE DATABASE pollsdb;
CREATE DATABASE
postgres=# CREATE USER manager WITH PASSWORD '########';
CREATE ROLE
postgres=# GRANT ALL PRIVILEGES ON DATABASE pollsdb TO manager;
GRANT
Download sample repository
$ git clone https://github.com/Azure-Samples/djangoapp.git
$ cd djangoapp
$ python manage.py makemigrations
No changes detected
$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, polls, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying polls.0001_initial... OK
Applying sessions.0001_initial... OK
$ python manage.py createsuperuser
Username (leave blank to use 'user'): admin
Email address: admin@localhost
Password:
Password (again):
Superuser created successfully.
Run server and acccess web page at http://127.0.0.1:8000/
$ python manage.py runserver
Performing system checks...
System check identified no issues (0 silenced).
January 25, 2020 - 16:42:14
Django version 2.1.2, using settings 'azuresite.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
[25/Jan/2020 16:42:26] "GET / HTTP/1.1" 200 111
[25/Jan/2020 16:42:26] "GET /static/polls/style.css HTTP/1.1" 200 27
Not Found: /favicon.ico
[25/Jan/2020 16:42:26] "GET /favicon.ico HTTP/1.1" 404 2688
Login zu Azure
$ az login
Deploy to App Service
$ az webapp up --sku F1 -n azure-toolbox-django-demo -l westeurope
webapp azure-toolbox-django-demo doesn't exist
Creating Resource group 'xx_xx_Linux_westeurope' ...
Resource group creation complete
Creating AppServicePlan 'xx_asp_Linux_westeurope_0' ...
Creating webapp 'flask-demo' ...
Configuring default logging for the app, if not already enabled
Creating zip with contents of dir .../Working-with_Django ...
Getting scm site credentials for zip deployment
Starting zip deployment. This operation can take a while to complete ...
Deployment endpoint responded with status code 202
You can launch the app at http://via-internet-django-demo.azurewebsites.net
{
"URL": "http:/azure-toolbox-django-demo.azurewebsites.net",
"appserviceplan": "xx_asp_Linux_westeurope_0",
"location": "westeurope",
"name": "azure-toolbox--django-demo",
"os": "Linux",
"resourcegroup": "xx_xx_Linux_westeurope",
"runtime_version": "python|3.7",
"runtime_version_detected": "-",
"sku": "FREE",
"src_path": ".../Working-with_Django"
}
The below code snippet we can view the result of using .map versus .switchMap
//user.service.ts
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from "rxjs";
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/do';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/debounceTime';
import 'rxjs/add/operator/distinctUntilChanged';
@Injectable()
export class UserService {
constructor(private http: Http) { }
getUsers(): Observable<any> {
return this.http.get('http://jsonplaceholder.typicode.com/users')
//.map(v => v.json());
.switchMap(v => v.json());
}
}
//app.component.ts
import { Component } from '@angular/core';
import { UserService } from "./user.service";
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
constructor(private userService: UserService) {
}
search(term: string) {
this.userService.getUsers()
.subscribe(v => console.log(v));
/*
//we can do this with .switchMap
this.userService.getUsers()
.subscribe(v => {if (v.email != "Sincere@april.biz") {
console.log(v.email);
}});
*/
}
}
Solving the multiple Async Pipe in Angular ≥ 2.0.0 with share operator
Remember to import import "rxjs/add/operator/share"; See reference here.
squareData$: Observable<string> = Observable.range(0, 10)
.map(x => x * x)
.do(x => console.log(`CalculationResult: ${x}`)
.toArray()
.map(squares => squares.join(", "))
.share(); // remove this line: console will log every result 3 times instead of 1
Managing Cold and Hot Observables using publish().refCount() which is similar to .share()
ngOnInit() {
// in angular 2 and above component.ts file add these this.coldObservable();
this.hotObservable();
}
/*
* cold observable is like a recast of video
* */
coldObservable() {
let incrementalObs = Observable.interval(1000).take(10).map(x => x + 1);
incrementalObs.subscribe(val => console.log('a: ' + val));
setTimeout(function() {
incrementalObs.subscribe(val => console.log(' b: ' + val));
}, 4500);
}
/*
* hot observable is like watching a live video
* */
hotObservable() {
let incrementalObs = Observable.interval(1000).take(10).map(x => x + 1).publish().refCount(); //can also use .share()
incrementalObs.subscribe(val => console.log('a: ' + val));
setTimeout(function() {
incrementalObs.subscribe(val => console.log(' b: ' + val));
}, 4500);
}
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
title = 'app works!';
obs = Observable.of(1, 2, 3, 4);
ngOnInit() {
this.howToHandleErrorV1();
this.howToHandleErrorV2();
this.howToUseRetry();
this.mergeObservableAndThrowError();
this.mergeObservableAndErrorResumeNext();
this.mergeObservableAndErrorCatch();
}
/*
* This uses Catch for V1. This introduces Closure. It is effectively the same as V2.
* */
howToHandleErrorV1() {
this.obs
.map(x => {
if ( x === 3 ) {
throw 'I hate threes'; // When it hitted error it actually unsubscribe itself at x === 3 of throw error
}
return x;
})
.catch(err => Observable.throw('Caught error here Observable.throw')) // continue go down the error path use Observable.throw
.catch(err => Observable.of('Caught error here Observable.of')) // catch just use Observable.of
.subscribe(
x => console.log(x),
err => console.error(err), // If not catch any where, the I hate threes errors will be propagated to here
() => console.log('done completed')
);
}
/*
* There is a difference between V1 and V2. For V2 it is using onErrorResumeNext which
* */
howToHandleErrorV2() {
let good = Observable.of('Caught error here Observable.of');
this.obs
.map(x => {
if ( x === 3 ) {
throw 'I hate threes'; // When it hit error it actually unsubscribe itself at x === 3 of throw error
}
return x;
})
.onErrorResumeNext(good) // To catch just use Observable.of
.subscribe(
x => console.log(x),
err => console.error(err), // If not catch any where, the I hate threes errors will be propagated to here
() => console.log('done completed')
);
}
/*
* For this we use see it retries three times then console.error(err);
* So retryWhen is for trying network connection websocket
* */
howToUseRetry() {
this.obs
.map(x => {
if ( x === 3 ) {
throw 'I hate threes'; // When it hitted error it actually unsubscribe itself at x === 3 of throw error
}
return x;
})
.retry(3) // retry three times
.retryWhen(err => err.delay(2000).take(3)) // similar but with 2 seconds delay and the error is not propagated.
.retryWhen(err => err.delay(2000).take(3).concat(Observable.throw('bad'))) // this it would throw an error.
.subscribe(
x => console.log(x),
err => console.error(err), // If not catch any where, the I hate threes errors will be propagated to here
() => console.log('done completed')
);
}
/*
* Using observable merge operator
* */
mergeObservableAndThrowError() {
let mergedObs = Observable.merge(
this.obs, //1, 2, 3, 4
Observable.throw('Stop Error'),
Observable.from(this.array), //0, 1, 2, 3, 4, 5
Observable.of(999) //999,
);
mergedObs.subscribe(
val => console.log(val), //this should show 1, 2, 3, 4, Stop Error
error => console.log(error),
() => console.log("completed")
);
}
/* Using observable onErrorResumeNext just like merge operator
* */
mergeObservableAndErrorResumeNext() {
let mergedObs = Observable.onErrorResumeNext(
this.obs, //1, 2, 3, 4
Observable.throw('Stop Error'),
Observable.from(this.array), //0, 1, 2, 3, 4, 5
Observable.of(999) //999,
);
mergedObs.subscribe(
val => console.log(val), //this should show 1, 2, 3, 4, 0, 1, 2, 3, 4, 5, 999
error => console.log(error),
() => console.log("completed")
);
}
/*
* Using observable merge operator and catch
* */
mergeObservableAndErrorCatch() {
let mergedObs = Observable.merge(
this.obs, //1, 2, 3, 4
Observable.throw('Stop Error'),
Observable.from(this.array), //0, 1, 2, 3, 4, 5
Observable.of(999) //999,
).catch(e => {
console.log(e);
return Observable.of('catch error here');
});
mergedObs.subscribe(
val => console.log(val), //this should show 1, 2, 3, 4, Stop Error, Catch Error Here
error => console.log(error),
() => console.log("completed")
);
}
}
map vs flatMap in RxJS
Transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable. See my GitHub repo.
obs = Observable.of(1, 2, 3, 4);
ngOnInit() {
this.usingMap();
this.usingMapToMakeInnerObservable();
this.usingMapAndMergeAll();
this.usingFlatMap();
}usingMap() {
this.obs
.map(x => x * 2) // transform the input by multiple of 2
.subscribe(
x => console.log(x),
err => console.error(err),
() => console.log('done completed')
);
}
usingMapToMakeInnerObservable() {
this.obs
.map(x => Observable.timer(500).map(() => x + 3)) // transform the input wrapping it with another observable and addition of 3
//.map(x => Observable.timer(500).map((x) => x + 3)) // !!! REMEMBER Not the same as the immediate above
.subscribe(
x => console.log(x),
err => console.error(err),
() => console.log('done completed')
);
}
// Map and Merge all is the same as just one FlatMap
usingMapAndMergeAll() {
this.obs
.map(x => Observable.timer(500).map(() => x + 3)) // transform the input wrapping it with another observable and addition of 3
.mergeAll()
.subscribe(
x => console.log(x),
err => console.error(err),
() => console.log('done completed')
);
}
// Flat map is the same as map then merge all
// transform the items emitted by an Observable into Observables, then flatten the emissions from those into a single Observable
usingFlatMap() {
this.obs
.flatMap(x => Observable.timer(500).map(() => x + 10)) // transform the input wrapping it with another observable and addition of 10
.subscribe(
x => console.log(x),
err => console.error(err),
() => console.log('done completed')
);
}
Transforming pure Javascript array vs. Observable from array
array = [0, 1, 2, 3, 4, 5];
ngOnInit() {
this.setArrayToObservableThenTransform();
}/*
* This keeps creating new array. It is good that it creates new array of arr for immutability.
* But it's bad because there is clean up and resource intensive for mobile
* */
transformArray() {
let result = this.array
.filter(( x, i, arr ) => {
console.log('filtering ' + x);
console.log('is the source array ' + (arr === this.array));
return x
})
.map(( x, i, arr ) => {
console.log('mapping ' + x);
console.log('is the source array ' + (arr === this.array));
return x + '!';
})
.reduce(( r, x, i, arr ) => {
console.log('reducing ' + x);
return r + x;
}, '--');
console.log(result);
}
/*
* This is more efficient for resource management because it linearly scans and discard when not right
* */
setArrayToObservableThenTransform() { let obsArray = Observable.from(this.array); // Use Observable.from() instead of Observable.of(). There is diff. obsArray
.filter(( x: any ) => {
console.log('filtering ' + x);
return x
})
.map(( x ) => {
console.log('mapping ' + x);
return x + '!';
})
.reduce(( r, x ) => {
console.log('reducing ' + x);
return r + x;
}, '--')
.subscribe(
x => console.log(x)
);
}
array = [0, 1, 2, 3, 4, 5];ngOnInit() {
this.reduceArray();
this.reduceObservableArray();
this.reduceObservableArray_Abstract2();
this.scanObservableArray();
}
/*
* This is the same as reduceObservableArray()
* */
reduceArray() {
let result = this.array.reduce(
(accumulator, currentValue) => accumulator + currentValue, 3
); // 3 is the init value.
console.log('reduceArray ' + result); // output 18 => 3 + (0 ... 5)
}
/*
* This is the same as reduceArray()
* But this waits for all the arrays to finish emitting before reducing them to one single number
* See the next method to understand better
* */
reduceObservableArray() {
let obsArray = Observable.from(this.array);
obsArray.reduce(
(accumulator, currentValue) => accumulator + currentValue, 3
).subscribe(
val => console.log('reduceObservableArray ' + val)
);
}
/*
* The exact same reduce function/method as of reduceObserableArray() above
* This proves that it waits for all 6 numbers to come in then reduce them
* */
reduceObservableArray_Abstract2() {
let obsArray = Observable.interval(1000).take(6); //emits 6 times of 0, 1, 2, 3, 4, 5
obsArray.reduce(
(accumulator, currentValue) => accumulator + currentValue, 3
).subscribe(
val => console.log('reduceObservableArray_Abstract2 ' + val)
);
}
/*
* This is the same as the above reduceObserableArray_Abstract2()
* except this is using scan instead of reduce
* */
scanObservableArray() {
let obsArray = Observable.interval(1000).take(6); //emits 6 times of 0, 1, 2, 3, 4, 5
obsArray.scan(
(accumulator, currentValue) => accumulator + currentValue, 3
).subscribe(
val => console.log('scanObservableArray() ' + val)
);
}
Create, next, and subscribe to Subject and BehaviorSubject
There is a Stack Overflow thread which discussed about the difference between Subject and BehaviorSubject. It’s worth understanding.
import { Subject } from 'rxjs/Subject';
import { BehaviorSubject } from "rxjs/BehaviorSubject";
// create subject
// there is no need for initial value
subject = new Subject<boolean>();
// create behaviorSubject which require initial value
// true is an initial value. if there is a subscription
// after this, it would get true value immediately
behaviorSubject = new BehaviorSubject<boolean>(true);
ngOnInit() {
this.subject.next(false); /* Subject subscription wont get anything at this point before the subscribeSubject() */ this.subscribeSubject();
this.subscribeBehaviorSubject();
}
/*
* Push the next val into the behavior subject
* */
nextSubject(val: boolean) {
this.subject.next(val);
}
/*
* Any values push into the subject would not be can shown
* before this subscribeSubject() is called
* */
subscribeSubject() {
this.subject
//.take(1) //when we include .take(1) we will have a complete. Without this it will continue subscribing
.subscribe(
val => console.log(val),
err => console.error(err),
() => console.log('completed')
);
}
/*
* This is the proper way to return a subject as observable
* */
getSubject(): Observable<boolean> {
return this.subject.asObservable();
}
/*
* Push the next val into the behavior subject
* */
nextBehaviorSubject(val: boolean) {
this.behaviorSubject.next(val);
}
/*
* For angular Behavior subject for a data service as a angular service often initializes
* before component and behavior subject ensures that the component consuming the
* service receives the last updated data even if there are no new
* updates since the component's subscription to this data.
* */
subscribeBehaviorSubject() {
this.behaviorSubject
// .first()
.subscribe(
val => console.log(val),
err => console.error(err),
() => console.log('completed')
);
}
usingFinallyOperator() {
Observable
.interval(500)
.take(4)
.finally(() => console.log('End of the observable, Hello World'))
.subscribe(
val => console.log('count taker ' + val)
);
}
Stopping / Intercepting Observable
Imagine using Gmail where it allows you to undo email sent? We can produce similar experience with Observable
// subscription is created when an observable is being subscribed
subscription: Subscription;
// boolean variable for showing stop observable using takeWhile operator
isTrue: boolean = true;
/*
* basic interval can be used as delay too
* Imagine Gmail allows you to send and undo send within 4 seconds of sending
* Use Case: Perform an action 8 seconds later then intercept if user choose to undo the action
* */basicInterval() {
let undoInSeconds: number = 8;
this.subscription = Observable
.interval(1000)
.take(undoInSeconds)
.takeWhile(() => this.isTrue)
.subscribe(
(val: number) => {
console.log(`${val + 1} seconds... UNDO`);
( val === (undoInSeconds - 1) ) ? console.log('Email sent / Action performed') : null;
}
);
}
/*
* This is to stop observable from continuing performance
* Use Case: Stop observable from running like how Gmail could undo email being sent
* */stopObservableUsingUnsubscribe() {
if (!!this.subscription) {
this.subscription.unsubscribe();
console.log('subscription: Subscription is unsubscribed');
}
}
/*
* This is also to stop observable from continuing performance
* This method is more preferable than subscribing method then unsubscribe
* Use Case: Stop observable from running like how Gmail could undo email being sent
* */stopObservableUsingTakeWhile() {
this.isTrue = false;
}
Perform conditional Reactive Form validation
This is my approach to performing conditional validation when using Angular. We will minimally manipulate the Observable of RxJS in this example. Let’s try by creating or using app.component.ts.
1 . Create a form that has two form controls reason and otherReason.
/* * Refer to angular official guide at https://angular.io/guide/reactive-forms on how to create reactive form with form controls * */createForm() {
this.form = this.formBuilder.group({ reason: ['', Validators.required ],
otherReason: [''], });
}
2 . Create two methods addValidator and removeValidator.
/* * For conditional form validation use * */
private addValidator( control: AbstractControl, newValidator ){
let existingValidators = control.validator;
control.setValidators(Validators.compose([ existingValidators, newValidator ]));
control.updateValueAndValidity();
}
/* * For conditional form validation use * */
private removeValidator( control: AbstractControl ){
control.clearValidators();
control.updateValueAndValidity();
}
3 . Create third method called conditionalFormValidation.
The outcome should illustrate that if we select ‘Others’ option in the dropdown list of reason, it should make otherReason form control field as required.
Perform manual operations after reading from Firebase database
When using AngularFire2 with Angular + Firebase, in getting a list of data from Firebase, we will get one observable instance but within that one observable is an array of N size. We can manually filter the array inside that one observable instance using arr.filter. It is different from RxJS .filter operator. Of course we can also flatten what is inside an array using .flatMap() operator. However, we’re going use JavaScript array filtering, instead of non-observable filtering, right after getting an observable object.
We can also reverse an array using JavaScript array reverse function. See reference. On a side note, using negative timestamp to reverse Firebase display is also another option.
Besides those above, we can also use the response returned from AngularFire2 to perform “local filter/search”. This result can be valuable for autocomplete filtered list or searches. However, this approach below suffers severely in performance issue where at the magnitude of the size of the returned response from AngularFire2. E.g. if the list has N items. It has to iterate at least 1N. Perhaps an average of 2N.
The task of creating an error free program is not easy. And, if your program runs free of errors, keeping it error-free after an update or change is even more complicated. You don’t want to insert new errors or change correct code with wrong parts.
The answer to this situation (directly from the Oracle of Delphi) is: Testing, Testing, Testing
And the best way to test is to start with tests.
This means: think about what the result should be and then create a Test that checks this. Imagine, you have to write a function for adding two values, and you should describe the functionality.
So, maybe, your description contains one or two examples:
My functions add’s two numbers, e.g 5 plus 7 is 12 (or at least should be 12 :))
The procedure with the TDD is:
think and define, what the function should to
write a stub for the function, e.g. only function parameters and return type
write a function, that tests you function with defines parameters and know result
For our example above, this means:
Write the python script with the desired functionality: src/main.py
def add(val1,val2):
return 0 # this is only a dummy return value
Write the Python Testscript: tst/main.p
def_test_add():
result = add(5,7)
if (result = 12):
print("everything fine")
else:
printf("ups, problems with base arithmetics")
Now, with these in your toolbox, you can always verify your code by running the tests.
$ python test_add.py
ups, problems with base arithmetics
dfdf
Setup virtual environment
Mostly, tests are repeated after every change. So, to be sure, that each test is running the same way and with the same environment, we will use pythons virtual environment feature to create a new fresh python environment for the tests.
Create virtual environment
$ python3 -m venv .env/python
Activate environment
Add the following line to .bashrc (or .envrc if you are using direnv)
At least, create a simple Calculator: src/CalculatorLib/Calculator.py
class Calculator:
def __init__(self):
print("Init Calculator")
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
def multiply(self, a, b):
return a * b
def divide(self, a, b):
return a / b
def power(self, base, exp):
return base ** exp
Create the Main App for your Calculator: src/main.py
from CalculatorLib.Calculator import Calculator
class Main(object):
def run(self):
c = Calculator()
print("5 + 3 =
print("8 - 4 =
print("5 * 3 =
print("8 / 4 =
print("8 ^ 4 =
if __name__ == '__main__':
Main().run()
Yur done with the fist development step. Try your app:
Now, implement the function correctly and startover the test:
Add a function at the end of your Calculator: src/CalculatorLib/Calculator.py
import math
class Calculator:
...
def factorial(self, n):
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result, factor = 1, 2
while factor <= n:
result *= factor
factor += 1
return result
from radish import given, when, then
@given("I have the numbers {number1:g} and {number2:g}")
def have_numbers(step, number1, number2):
step.context.number1 = number1
step.context.number2 = number2
@when("I sum them")
def sum_numbers(step):
step.context.result = step.context.number1 + \
step.context.number2
@then("I expect the result to be {result:g}")
def expect_result(step, result):
assert step.context.result == result
"""
The example module supplies one function, factorial(). For example,
>>> factorial(5)
120
"""
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
if __name__ == "__main__":
import doctest
doctest.testmod()
$ nosetests -v
test_base.test_should_pass ... ok
test_base.test_should_raise_error ... ok
test_base.test_check_if_true_is_true ... ok
test_base.test_check_if_inc_works ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
from flask import Flask
app = Flask(__name__)
@app.route('/')
def example():
return '{"name":"Bob"}'
if __name__ == '__main__':
app.run()
Start Flask
flask run
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
127.0.0.1 - - [01/Aug/2019 12:19:00] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [01/Aug/2019 12:19:00] "GET /favicon.ico HTTP/1.1" 404 -
We use cookies on our website to give you the most relevant experience by remembering your preferences and repeat visits. By clicking “Accept All”, you consent to the use of ALL the cookies. However, you may visit "Cookie Settings" to provide a controlled consent.
This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary cookies are absolutely essential for the website to function properly. These cookies ensure basic functionalities and security features of the website, anonymously.
Cookie
Duration
Description
cookielawinfo-checkbox-analytics
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Analytics".
cookielawinfo-checkbox-functional
11 months
The cookie is set by GDPR cookie consent to record the user consent for the cookies in the category "Functional".
cookielawinfo-checkbox-necessary
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookies is used to store the user consent for the cookies in the category "Necessary".
cookielawinfo-checkbox-others
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Other.
cookielawinfo-checkbox-performance
11 months
This cookie is set by GDPR Cookie Consent plugin. The cookie is used to store the user consent for the cookies in the category "Performance".
viewed_cookie_policy
11 months
The cookie is set by the GDPR Cookie Consent plugin and is used to store whether or not user has consented to the use of cookies. It does not store any personal data.
Functional cookies help to perform certain functionalities like sharing the content of the website on social media platforms, collect feedbacks, and other third-party features.
Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.
Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics the number of visitors, bounce rate, traffic source, etc.
Advertisement cookies are used to provide visitors with relevant ads and marketing campaigns. These cookies track visitors across websites and collect information to provide customized ads.