레이블이 javascript인 게시물을 표시합니다. 모든 게시물 표시
레이블이 javascript인 게시물을 표시합니다. 모든 게시물 표시

2016년 5월 1일 일요일

동적 웹컨텐츠 크롤링

최근에 간단한 웹크롤러를 만들고 있는데, 동적 웹컨텐츠를 크롤링하는 방법을 정리한다.  이 블로그에서( http://yujuwon.tistory.com/entry/PhantomJS-사용하기) 설명한 것처럼 PhantomJS을 사용하였다.

1. 동적 웹컨텐츠

아래와 같이 파이어폭스의 개발자 도구의 "네트워크" 텝을 켜서 보면, 응답의 형식이 html이 아닌, json 이나 xml 인 경우가 있다. 브라우저가 이러한 응답을 읽어서 내용을 표시해주는데 보통의 ajax 방식으로 로딩되는 경우가 이러한 경우이다. 이런 경우는 소스에서 Request 을 하는 url 을 찾기 쉽지 않다. 그래서 PhantomJS 와 같은 브라우저를 이용해서 웹페이지를 로컬로 임시로 저장해서 그것을 크롤링 하는 방법을 사용해보기로 한다.  더 좋은 방법이 있을법도 한데, 일단 동작하는 프로그램을 빨리 만들어보자.
























2. PhantomJS

맥에서 PhantomJS을 사용하려면 소스코드를 다운받고 빌드를 해주어야 한다. 아래 문서를 참고하자. http://phantomjs.org/build.html

git submodule update 까지 해주고 실행하고 build을 하려고 하면 OpenSSD, Xcode 등이 없다고 빌드가 되지 않는다. 다 설치해주고 나서 build 을 해주자. build 는 조금 시간이 걸린다. 


그리고 나서 phantomjs을 이용해서 웹페이지를 로컬로 저장해보자. 간단한 js 스크립트를 이용해서 저장을 한다. 위의 소스코드는 "http://yujuwon.tistory.com/entry/PhantomJS-사용하기" 에서 복사해온 것이다. 그리고 나서 아래처럼 실행해보자.

➜  phantomjs git:(d9cda3d) ./bin/phantomjs save_web.js http://sports.news.naver.com/wfootball/news/index.nhn

공식문서의 아래 문서를 참조하면 도움이 된다.
http://phantomjs.org/screen-capture.html

3. 크롤링 라이브러리

크롤링 하는 프로그램은 scrapy 라는 파이썬 라이브러리를 이용해서 작성하고 있다. 여러모로 편리하다.
http://scrapy.org



2015년 9월 6일 일요일

Javascript Guide

Recently, I have been developing web app using AngularJS. But it have been long time since I used javascript. So, I just write learning test after study MDN to remind my memory :-). If you click each title, you can access actual topic.

1. Write javascript test case with Jasmine

How to write javascript test case using jasmine and run it.

Basic grammar of javascript. dynamic typing, variable, object, arrray, etc

Define function, Call by value, Call by reference, arguments, closure

Block scope, try catch, falsy value

continue-break, for..in, for..of statements

expression and operator like equal, strict equal, negation, plus, typeof, void

Declare array, itereate, attribute and related method like concat, push, etc.

Attributes of map and set, difference with object

How to create object, attribute, iterate attribute

Javascript object model and prototype inheritance, constructor function, instanceof and many related concepts.

Development environment using npm, grunt, karma, jasmine

Javascript CI using jenkins, git, gerrit, phantomjs, npm, grunt, karma, jasmine


Javascript Continuous Integration


We'll see how to setup javascript continuous intergration environment using jenknin, git, gerrit.

1. Add PhantomJS to  package.json

PhantomJS can execute javascript without browser. Need to add PhantomJS to run test-case upon PhantomJS


npm install phantomjs --save-dev
npm install karma-phantomjs-launcher --save-dev
npm install karma-junit-reporter --save-dev


2. Create separated karma config file

We'll create separate karma config file for jenkins. Let's create "jenkins-ci-conf.js" like followings. Set browser to phantomjs like line [line 63].




3. Create grunt task for jenkins CI

Create grunt task for Jenkins. In this example, I create "continuous" task. Look at [line 23 ~ 26] closely. Change karma config file to "jenkins-ci-conf.js". We have to use "singleRun". The "singleRun" options means that Continuous Integration mode. You can exectue the task like following command,
grunt karma:continuous


4. Build PhantomJS [If jenkins is installed linux]

If you jenkins is installed to linux, you need to build it. But you use other environment, you don't need to build. Refer PhantomJS in detail.


5. Install jenkins plugins [If jenkins is installed linux]

Install Environment Injector Plugin. It is useful to configure PhantomJS path.


6. Job configuration

Let's see job configuration. I used git as a source code management.

Source code management



















build trigger






gerrit trigger




























Build environment
set phantomJS path in script content



















Build
There are two steps in build script. The first one is install dependents module using npm install. The second one is execute grunt task like "grunt karma:continuous"














Action after build
Set path to generate test result report












7. execute result.

































javascript development environment

We'll see how to setup javascript development and test environment using npm, grunt, karma, jasmine.


1. nodejs

We will not use nodejs directly. But there are many useful tool which operated on nodejs platform. Let's install nodejs first. You can easily install nodejs after downloading binary it.


You can install nodejs for linux(Ubuntu 14.04.02 LTS) like followings,

Download node-install.sh
wget https://github.com/taaem/nodejs-linux-installer/releases/download/v0.3/node-install.sh

Add exe authority 
chmod +x node-install.sh

Execute
./node-install.sh


2. npm and package.json

The npm helps developer to share their code and  to reuse module. Those code called package or module. They are shared by registering npm registry. The npm registry is a kinds of database which contains package information. The package is a module directory. The package.json is in that folder, this fils contains meta information of package. When you create javascript application, you might use those package(module). With npm and package.json, you can easily compose those module and share environment with your colleague.

3. package.json

You can crate package.json using following command. It doesn't matter create it manually. Refer this.


npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (myjavascriptproject) hellojavascript
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Some/Pth/package.json:

{
  "name": "hellojavascript",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes

4. karma & jasminie

karam is automatic test executor which is made by AngularJS team of google. You can install in following command,

npm install karma --save-dev

We will write test-code using jasmine javascript test framework. Refer the usage of jasmine which i wrote before.

npm install karma-jasmine --save-dev

With --save-dev, all dependent module are updated to package.json automatically. We'll add required module this way. We can execute test-case just using karma itself. But in this post, we will execute karma using grunt.

Let's make karma configuration file.

karma init my.conf.js

Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine

Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no

Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome

What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.

Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.

> yes

You can define src files and test file to include like [line 17]


5. grunt

Install grunt which is javascript build tool. Grunt is useful for many reasons. Let's install following modules.

install grunt 
npm install grunt --save-dev
npm install grunt-cli --save-dev

grunt-karma plugin
npm install grunt-karma --save-dev

To run test-case in chrom browser, neet to install following plug-in.
npm install karma-chrome-launcher --save-dev

Install addtional plug-ins. jshint display javascirpt grammer warning and errors

npm install grunt-contrib-jshint --save-dev
npm install grunt-contrib-watch --save-dev

Grunt configuration
Gruntfile.js is a grunt confugration file. In [line 4], Grunfile.js read package.json. From the next line, configure jshint, watch, karma task. You can run specific task like followings,

grunt [task name]

run karma task.

grunt karma

6. directory structure and package.json

All directory structure which i used like followings,























The node_modules directory don't need to manage by source manage tool(git or svn). Because you can create same directory structure using package.json with npm. When you do build and test using CI tool like jenkins, this is a quite convenient. Let's simply test it. Copy package.json to another directory and execute following command.

npm install

Then npm will install required module after reading package.json



Javascript object model and inheritance


Let's see Javascript Object model and Inheritance. We'll see Javascript specific things and something is good to know. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it. 

Class based object model and prototype based object model
   
There is clear concept in programming language which use class based object model. It is class and instance. The class abstract characteristics of  objects which are in specific set(or category) using member variable and method. For example, The "Talent class" abstract general attributes of who have talented some area. On the other hand,  The instance represents one of talented people. "SteaveJobs instance" is that the actual instance of "Talent class" type. It have all attributes of "Talent class".

Like Javascript, the programming language which use prototype based object model, there is no clear distinction between class and instance. They are just an object. In those language, there is the object which can be a prototype. This prototype object become a template of other objects. Any object can be a prototype of other object in run-time or compile time. Objects which are created by prototype, they are share properties of prototype.

When you create object in javascript, you don't need to define class separately like we do in java. Instead of that, you can define attributes of object using "constructor function". Any javascript function can be a constructor function, you can create new object using constructor function with "new" keyword

Class-based
Prototype-based
Distinguish class and instance
All object can be inherited from other object
Need explicit class definition. Instance can be created by constructor.
Object definition and creation can be possible using "constructor function"
Create one object with new keyword
same
Define inheritance structure like subclass using class definition.
Define inheritance structure by assign prototype object with constructor function
Not possible to add attribute in runtime.
Possible to add/remove attribute in runtime


I'll use following inheritance structure as an example.



1. Inheritance

Let's see Painter object which inherit from Talent object. As see in [line 10], Talent.call(this) method is called in Painter object. About call function, look at this. You can call the "construct function" of Talent with"this" and additional arguments. Then, as see in [line 13], Talent.prototype is assigned to Painter.prototype. The prototype property is a special attribute in javascript, all function have this attribute. (Just for your reference, the function is declared like  function finctName {...} but not assigned to attribute of some object. The method is a function which is assigned to attribute of object.)

Let's see javascript internal object creation procedure. 

var psy = new Singer;

If there is new keyword, create generic object and make it as the value of this keyword in Signer's constructor function. Then, the "majorTalent" attribute is assigned explicitly in constructor function. In that order, the __proto__ attribute is assigned to the prototype attribute of Singer's constructor function implicitly.(The __proto__ attribute determine prototype which contains attribute to be returned)

When javascript read some attribute, javascript check the attribute in object first. If the attribute is not exist in object, javascript check prototype chain using __proto_ attribute. If the object in prototype chain have the attribute, javascript return it. If the property is not exist in prototype chain, javascript say that the attribute is not exist.


2. More flexible object creation - constructor function with arguments
Make constructor function can receive arguments.


3. More flexible object creation - default value
As see in [line4 ~ line6], you can set default value using "||" operator. If there is a value, it is used. But if there is no value, empty value is used as a default. The constructor function of Talent object is assigned to base attribute like [line 11]. The base attribute is not a special attribute. Any name is possible. Then, call constructor function in [line 12]

4. why we should assign "prototype" attribute explicitly?
Let's see TalentedForMusic and TalentedForPaint closely. The prototype attribute of TalentedForMusic is not assigned as its parent's prototype. Look at [line 43 - 46]. If you add additional attribute of Talent.prototype, the hummingMan object which instance of TalentedForMusic don't have this attribute. i.e. The attribute is not added since TalentedForMusic don't have parent's prototype attribute.

5. "The property in constructor function" vs "object.prototype.property = vlaue"
Let's see "name" attribute and "grade" attribute closely. The "name" attribute is declared in constructor function, the "grade" attribute is declared as prototype property like "Talent.prototype.grade = "none". This is an important difference. As see in [line32 - 43], if you assign new value to name attribute, values of instances are not changed. On the other hand, if it declared as a prototype attribute like [line 46 - 48], values of its instances will be changed as new value is assigned.

6. instanceof, __proto__
As see in [line 38], you can find the class using instanceof keyword. All javascript object have __proto__ attribute except Object.(All javascript function have prototype attribute). When object is created, the prototype attribute of constructor function is assigned to __proto__ attribute. As see in [line 39 - 41], the __proto_ property of object is same with the property of constructor function.

7. Use global value in constructor function
You have to be careful when use global variable in constructor function. You might be expected the value of count 1 in [line 35], but it is 3 since it called [line32], [line29], [line17]. i.e. it is also called when assign prototype attribute.


8. Javascript doesn't support multiple inheritance.
You might assume that TalentForMusic constructor function crates two object Talent and Personality. Actually, it is possible to use of attributes of Personality from Personality. But as see in [line 35], if you add new attribute to Personality, this attribute is not added to TalentedForMusic.


9. Reference
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

2015년 9월 5일 토요일

Javascript object

Let's see Javascript Object. We'll see Javascript specific things and something is good to know. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it. 

1. Object and property
Javascript designed based on object which have simple form. The object is a collection of attributes. Those attribute have its own name and value. They are used to express many behavior and characteristics of object. Javascript variable can save not only value but also function itself, so that javascript can express behavior of object using method like ordinary object oriented language. The attribute can be expressed like below,  

objectName.propertyName

propertyName should be string or something can be converted to string.


2. Iterate attribute

You can iterates attributes of object using fon-in statement, Object.keys(o), Object.getOwnPropertyNames(o).

3. Create object

You can create object using initializer, construct function  or Object.create.

4. Prototype attributes
Every javascript object inherite "prototype" object. So, If you add attribute like [line 14], all instances of Male will have this attribute.

5. Define getter, setter

6. Delete attribute
7. Compare object
8. Reference
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

Javascript Map, Set

Let's see Javascript Map and Set. We'll see Javascript specific things and something is good to know. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it. 

1. map basic
You can iterate elements of map using for-of  statement. As see in [line 11], You can access the element using [key, value] form. The equality of key is evaluate both type and value using identity operator "===".

2. object vs map
Let's compare object and map. The attribute(key) of object should be defined using string, but map can use any type as a key. We can know the size of map using size method, but object need to iterate to calculate its size manually.

3. set basic
As you can see in [line 16], the key of map is also evaluate both type and value using identity operator "===".

4. array and set
As see in [line 5] , When convert array to set, duplicated element are removed except one.

5. Reference
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

Javascript Array

Let's see Javascript Array. There are many method related array . We'll see Javascript specific things and something is good to know. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it. 

1. Define array and access, attributes
You can create array object explicitly like [line 2]. It is also possible like [line 8] simply. Like [line 20], you can use any type of object as an array element. If you give other type which is not integer like [line 14, 15], it create attribute of object.

2. length
The length of array is a just last index + 1 as see in [line 5].

3. iteration
You can iterate element of array using for, for-each statement. Of course, you can use for-in statement.

4. concat, push, pop, join
5. shift, unshift
6. slice, splice
The splice function remove element which are in specific range and insert into new elements. You can see element 2, 3 are deleted from Array [1,2,3,4,5] and new element "a","b","c" are inserted. So the array contains [1,"a","b","c",4,5].

7. reverse, sort
8. indexOf, lastIndexOf
The lastIndexOf method start inspecting from last index of array.
9. forEach, map
It is useful when do some work using each element of array as an argument.
10. every, some, reduce
It is useful when do some inspecting work from whole range or specific range.
11. Array Generic Method
12. Reference
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html


2015년 8월 30일 일요일

Javascript Expression and Operators

Let's see Javascript expression and operator. You can learn the basic content from MDN's  Expressions and Operators . We'll see Javascript specific things and something is good to know. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it. 

1. equal, strict equal
If the type is different like [line5], Javascript try to converting type automatically since javascript is dynamic typing language. If you want to check equality with the actual type, you can use strict equal operator like [line 7].
2. negation, plus
The plus(+) operator convert to number.
3. string operator
4. delete operator
The "delete" operator delete specific property of object or specific index of array. The deleted object would be undefined like [line 9, line 15].
5. typeof
You can know the type using "typeof" operator.
6. void(expression)
The "void" operator evaluates expression like [line 5]. But don't return anything like [line6].
7. in operator
The "in" operator check whether specific element is contained in Object or Array.

8. Reference
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html


Javascript loop

Let's see javascript loop statements. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it.

1. label with continue, break
Javascript can define label. In [line 3],  "firstLoop" label is defined. This is useful when escape nested loop statement. The "break" statement in [line 9] make to escape of the First(for) loop, The second break in [line 13] make to escape loop(while) statement. This is same as in "continue" statements as well.

2. for - in statement
Property name is used in "for - in" statement if the element are Object. If element is array, index is used. In [line 8], p have the attribute name of object and can access the value of property like [line 9]. The [line 22] shows how to use it in Array.

3. for - of statement
The for - of  statement retrieve its element like [line 6] without index.

4. Reference
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

Javascript Block Scope, Falsy Value, Error Handling

Let's see javascript block scope( {...}), False values and throw, Error Handling statements. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it.

1. Javascript don't have Block Scope before ECMAScript6



2. Falsy value

false, undefined, 0, empty string(""), NaN are treated as a false.

3. Throw expression, try - catch - finally

Javascript can throw any expression using "throw" keyword. The throwed expression can be used in catch statement like [line 15], [line 43]. You can see how to use try - catch -finally statements.

4. Error Object

You can throw Error Object easily.

5. Reference

- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

Javascript Function

Let's see javascript function and its usage. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it.


1. Define function and its usage


Define function in javascript is nothing special. Let's see [line 8] closely. The function can be assigned to variable. It means that function can be a argument of another function just like a variable. It is also possible call like [line 11]. It this case, The name of variable which have a function as a value would be a the name of function.


2. call by value, call by reference

If the argument is primitive type, call by value is used. If the argument is non-primitive type like array or object, call by reference is used.

3. Arguments

Javascript don't support function oveloading. See [line 6]. You can know the reason. If more arguments are used than defined when call function, the other argument which are not defined wouldn't be used. You can know what values are used as a argument using "arguments" object. Refer "func2" in following example.


4. Closure

Javascript have the concept of closure. The "inside" function is defined in "outside" and "outside" function return the "inside" function itself. Variable "a" which is argument of "outside" can be referred in "inside" function.  You can call it like [line 9] and [line 10].


5. Reference 

- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

Javascript Type and Grammar


Let's see basic type and grammar of javascript. I assume that reader of this document have a basic programming experience. so, I will not explain everything in detail. We'll see javascript specific things and something is good to know. Learning test is written using Jasmine. Please refer Jasmine usage which I wrote before if you have interest it.

1. Javascript is dynamic typing programming language

It means that you don't need to specify type whenever declare variable. The type will be converted in run-time. In following example, We just use keyword "var" without specifying any type. It is also possible to use without explicit type casting. (Of course, programmer should careful when use it)

2. Variable

If you declare variable without "var", It means that you declare global variable. Please refer [line 9] , [line13] of following example closely.


3. undefined, null

If you just declare variable but not to assign any value, it will be treated as  "undefined". But depend on context, you can see that undefined and null are converted dynamically. "undefined" is treated as NaN(Not a Number) in decimal context. But "null" is  treated as  0.



4. constant

The variable name and function name which are declared with "constant" cannot be redeclared.


5. Array

Javascript Array is quite similar with general programming's array. Let's see [line 6]. If there are no value, it is treated as an undefined.

6. Object

You need to see how to declare object and how to access its member closely. Like [line 9], If the member's name is decimal,  You can use it like Array. But, if the name is not decimal, you should use like [line 4] or [line6]. You cannot use like [line 8]. It will cause javascript error.


7. Reference

- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript

- Jasmine - http://jasmine.github.io/2.3/introduction.html

2015년 8월 25일 화요일

Write javascript test case with Jasmine

Jasmine is one of the javascript test-framework. As described in official introduction documents, It is a  "Behavior-Driven JavaScript Test Framework" and it provides many useful API to write test case easily. If you have a experience about junit in java world, you can easily learn it.

Whenever I learn new programming language, I have been trying to learn its unit-test framework first. It is a quite useful. By writing learning test case from the very beginning of learning, you can easily learn how to test it with basic knowledge of your programming language. In most of cases, the code that easy to test is more easy to maintain. Well-made test cases can be a specification of user's requirements. It is more useful than well-made document. As application is going forward, it can be guard to protect legacy functionality.  


1.Write test case

Jasmine test have a following structure. You can define test suite with "describe" method. It can have many test cases. Each of test case is defined by "it" method. The first argument of "it" method like [line 2], It is a description of test case. The second argument is a function which is called when this test case is executed. The expected result of logic or expected return value of function can be defined in "expect" method. With "toBe" method, you can call actual logic or function which you want to test. Not only "toBe", but Jasmine also provides many useful Matcher and API. You can find details in API documents


2. Execute test case

Then, How can we execute test case? You need to download Jasmine from release page. There is a zip file. In there, you can find "SpecRunner.html". As see in [line 15], it includes source files which contains some logic. [line 18] includes test case file which contains test case to test logic or function in source files.

If open "SpecRunner.html" with web browser, you can see the followings,


























3. Tools

Debugging and checking console logs are very routine work when we do programming. Chrome and Firefox provides very convenient tools for this. Below is developer tool of Chrome browser.











My mother language is not english. Please understand my poor english. :D 

2015년 8월 16일 일요일

자바스크립트 개발환경 설정 : npm, grunt, karma, jasmine, etc

이 문서에서는 npm, grunt, karma, jasmine 을 이용해서 javascript 의 개발 및 테스트 환경을 구성하는 방법에 대해서 알아본다.


1. nodejs

nodejs 을 직접적으로 사용하지는 않을 것이지만, 자바스크립트에 개발에 여러 유용한 도구들이 nodejs 플랫폼 위에서 동작하는 것이 많다. 일단 node js 을 설치하자. 대부분의 환경에서는 nodejs 홈페이지에서 바이너리를 다운받아 쉽게 설치할 수 있다.

리눅서 서버 (Ubuntu 14.04.02 LTS) 에는 아래와 같은 방법으로 설치할 수 있다.

node-install.sh 다운받기
wget https://github.com/taaem/nodejs-linux-installer/releases/download/v0.3/node-install.sh

실행권한 추가
chmod +x node-install.sh

실행
./node-install.sh


2. npm 과 package.json

npm 은 자바스크립트 개발자가 쉽게 코드를 공유하고, 재사용할 수 있게 만드는 도구이다. 이 코드들은 패키지 또는 모듈이라고 불리우는데, npm 레지스트리에 등록되어서 공유된다. npm 레지스트리는 패키지들의 정보를 담고 있는 데이터베이스이다. 패키지는 일종의 모듈 폴더이다. 패키지는 package.json 이라는 파일이 있는데, 이 파일이 패키지에 대한 메타 정보를 포함하고 있다. 자바스크립트 애플리케이션을 만들때, 이런 패키지(모듈)들을 사용해서 애플리케이션을 구축하게 된다. npm 과 package.json  을 이용해서 이런 모듈들을 쉽게 구성할 수 있고, 동료 개발자와도 환경공유도 쉽게 도와준다.

3. package.json

아래 명령어를 통해서 package.json 을 만들 수 있다. 메뉴얼로 만들어도 상관없다. 이 동영상을 참고하자.

npm init

This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sane defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg> --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (myjavascriptproject) hellojavascript
version: (1.0.0) 
description: 
entry point: (index.js) 
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /Some/Pth/package.json:

{
  "name": "hellojavascript",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this ok? (yes) yes

4. karma & jasminie

karma 는 구글의 AnuglarJS 팀에서 만든 테스트 자동으로 실행하는 도구이다. 아래의 명령어를 통해서 설치할 수 있다.

npm install karma --save-dev

실제 테스트 코드는 jasmine 라는 자바스크립트 테스트 프레임워크를 사용할 것이다. 자스민의 사용법에 대해서는 따로 정리한 포스트을 참고하자.

npm install karma-jasmine --save-dev

--save-dev 옵션을 주면, 필요한 모듈들의 의존성을 package.json 에 자동으로 업데이트 한다.
이런 방식으로 계속 필요한 모듈들을 추가해 나갈 것이다. karma 자체로도 테스트 실행이 가능하다. 하지만 이 포스트에서는 grunt 라는 툴과 연동을 하여 구성을 할 것이다.

자, 이제 karma 설정 파일을 만들자.

karma init my.conf.js

Which testing framework do you want to use ?
Press tab to list possible options. Enter to move to the next question.
> jasmine

Do you want to use Require.js ?
This will add Require.js plugin.
Press tab to list possible options. Enter to move to the next question.
> no

Do you want to capture any browsers automatically ?
Press tab to list possible options. Enter empty string to move to the next question.
> Chrome

What is the location of your source and test files ?
You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
Enter empty string to move to the next question.

Should any of the files included by the previous patterns be excluded ?
You can use glob patterns, eg. "**/*.swp".
Enter empty string to move to the next question.

Do you want Karma to watch all the files and run the tests on change ?
Press tab to list possible options.

> yes

[라인 17] 에서 브라우저에서 읽어올 소스 파일과 테스트 케이스 파일을 설정해준다.


5. grunt

grunt 라는 자바스크립트 빌드 툴을 설치한다. grunt 을 설치하면 여러모로 유용하게 사용할 수 있다. 아래 3개 모듈을 설치하자.

grunt 설치
npm install grunt --save-dev

grunt-karma plugin
npm install grunt-karma --save-dev

테스트 케이스을  크롬에서 실행하기 위해, 아래 플러그인도 설치해준다.
npm install karma-chrome-launcher --save-dev

몇 가지 플러그인도 추가적으로 설치하자. jshint 는 자바스크립트의 문법오류나 경고를 표시해주는 플러그인다.

npm install grunt-contrib-jshint --save-dev
npm install grunt-contrib-watch --save-dev

Grunt 설정
Gruntfile.js 에서 설정을 해주자.
[라인 4] 에서 package.json  을 읽어오게 한고 있다. 그 다음라인부터 각각, jshint, watch, karma 타스크(task) 을 설정하고 있다. [라인 21] 에서 karma 의 설정파일을 읽어오게 하고 있다. 특정 task의 실행을 아래와 같이 진행할 수 있다.
grunt [task name]

karma 타스크를 실행하자.

grunt karma

6. 폴더 구조 및 package.json

전체 폴더 구조는 아래와 같은 모습을 보이게 된다.





















실제로 node_modules 폴더 자체는 소스 관리 툴(git or svn...) 로 관리할 필요가 없다. 왜냐하면 package.json 만 있으면, npm을 언제든지 동일한 모듈들을 install 함으로 같은 구조로 만들 수 있기 때문이다. jenkins 과 같은 CI 툴을 이용해서 빌드 및 테스트를 수행할 때도 이 점은 매우 편리하게 적용된다. package.json 을 특정 폴더로 복사한 다음에 아래 명령어를 수행해보자.

npm install

그러면 npm 이 package.json 기술된 메타정보를 읽어, 필요한 모듈들을 설치할 것이다.


자바스크립트 개발 및 테스트 환경을 구성하는 방법에 대해서 알아보았다. 이 포스트에 기술된 내용은 로컬 환경에서 사용할 용도이다. Jenkins CI 을 이용하여 빌드 및 테스트를 자동화 할때에도 npm 과 grunt  모듈들이 유용하게 사용된다. 이것과 관련된 내용은 다른 포스트에서 따로 정리할 예정이다.

2015년 8월 14일 금요일

자바스크립트 오브젝트 모델 및 상속구조


자바스크립트의 오브젝트 모델 및 상속구조에 대해서 자세하게 살펴본다. 학습테스트는 자바스크립트 테스트 프레임워크인 자스민을 이용해서 작성되었다. 자스민에 대한 사용법은 이 전에 작성했던 "자스민 사용법" 글을 참조하자.

클래스 기반의 객체모델과  프로토타입 기반의 객체 모델

자바와 같은 클래스 기반의 객체 모델을 사용하는 언어에서는 두 가지 분명하게 구분되는 개념이 있다. 바로 클래스와 인스턴스이다. 클래스는 특정 집합에 속하는 객체들의 특성들을 멤버변수와 메서드로 추상화한다.예를 들어, Talent 클래스는 "재능이 있는 사람들" 의 일반적인 특성을 추상화 한다. 반면에 인스턴스는 특정 재능이 있는 사람 한 명을 나타낸다. 예를 들어 SteaveJobs는 Talente  클래스가 실체화된 인스턴스로 Talent 클래스의 모든 속성들을 가지고 있다.   

자바스크립트와 같은  프로토타입 기반의 객체 모델을 사용하는 언어에서는 클래스와 인스턴스의 명확한 구분이 없고, 단순히 오브젝트이다. 이러한 언어에서는 프로토타입이 되는 오브젝트가 존재한다. 그리고 프로토타입 오브젝트는 다른 오브젝트의 템플릿이 된다. 오브젝트가 생성이 될 때이던지, 실행시간이던지 어떤 오브젝트도 다른 오브젝트의 프로토타입이 될 수 있다. 프로토타입을 통해서 생성된 오브젝트는 프로토타입의 속성들을 공유한다.

자바스크립트에서 오브젝트를 만들 때, 자바에서과 같이 별도의 클래스를 정의할 필요없다. 대신 생성자 함수을 통해서 특정 속성들을 가지는 오브젝트를 정의할 수 있다. 어떤 자바스크립트 함수도 생성자 함수가 될 수 있으며,"new" 키워드와 생성자 함수를 이용해서 새로운 오브젝트를 생성할 수 있다.

Class-based
Prototype-based
클래스와 인스턴스가 구분된다.
모든 오브젝트는 다른 오브젝트로부터 상속될 수 있다.
명시적인 클래스의 정의가 필요하다. 클래스의 인스턴스화는 생성자를 통해서 가능하다.
생성자 함수를 통해서 오브젝트의 정의 및 생성이 가능하다.
new 연산자를 통해서 한 개의 객체를 생성한다.
동일하다.
클래스 정의를 통해서 서브클래스 및 클래스 상속구조를 정의한다.
생성자 함수와 함께 prototype 오브젝트를 할당함으로 상속구조를 정의한다.
실행시간에 동적으로 속성을 추가하는 것이 불가능하다.
생성자 함수나 prototype 은 단순히 최초 속성들의 집합만을 정의한다. 동적으로 속성을 추가하거나 제거하는 것이 가능하다.

이 포스트에서는 아래와 같은 상속구조를 가지는 예제를 이용할 것이다. 클래스 다이어그램에서 관해서는 UML 클래스 다이어그램 을 참조하자.



1. 상속구조
먼저 Talent 오브젝트와 이 오브젝트를 상속한 Painter 오브젝트를 살펴보자. [라인 10]을 살펴보면 Painter 오브젝트에서 Talent.call(this)  메서드를 호출하고 있다. call 함수에 대해서는 여기를 살펴보자. call 함수에 "this"  인자와 필요에 따라 추가적인 인자를 넘김으로서 상속받고자 하는 오브젝트의 생성자 함수를(여기서는 Talent ) 호출할 수 있다. 그리고 나서 [라인 13]에서 Painter.prototype 속성에 Talent.prototype 를 생성해서 할당해 주고 있다. prototype 은 자바스크립트에서 사용하는 특별한 속성으로서 모든 함수는 이 속성을 가지고 있다. 참고로 함수는 일반적으로 function funcName() {...} 으로 선언된 것을 의미하고, 메서드는 특정 오브젝트 멤버로서 존재하는 것을 의미한다.

자바스크립트의 내부적인 객체 생성과정을 살펴보자.

var psy = new Singer;

자바스크립트는 new 오브젝트가 있는 경우,  generic object을 생성해서 Singer 오브젝트의 생성자 함수의 this  키워드의 value 로 넘겨준다. 그리고 나서 생성자 함수에서 명시적으로 "majorTalent”속성을 할당한다. 그 다음으로 묵시적으로 내부적인 __proto__ 속성을 Singer 생성자 함수의 prototype 으로 할당한다. (__proto__ 속성은 특정 속성을 리턴할 때, 특정 속성의 값을 리턴하는  prototype 을 결정한다.)

자바스크립트에서 특정 속성을 읽을 때, 자바스크립트는 먼저 해당 속성이 오브젝트에 존재하는지 확인한다. 만약 있으면 해당 값을 리턴한다. 만약 없다면, 자바스크립트는 __proto__  속성을 이용해서  프로토타입 체인을 확인한다. 프로토타입 체인에 있는 오브젝트가 해당 속성의 값을 가지고 있으면, 그 값을 리턴한다. 만약 오브젝트가 프로토타입 체인에 존재하지 않으면, 자바스크립트는 해당 속성이 존재하지 않는다고 말한다.


2. 좀 더 유연한 객체 생성방법 - 생성자 함수에 매개변수 전달
생성자 함수가 인자를 받을 수 있게 하여 사용한다.


3. 좀 더 유연한 객체 생성방법 - 기본값 설정
[라인 4 ~ 6]에서와 같이 "||" 연산자를 이용해서 속성에 기본값을 설정할 수 있다. 값이 있는 경우에는 인자로 넘어온 값을 그렇지 않은 경우에는  empty 값을 설정한다. [라인 11]에서는 base 속성에 Talent 오브젝트의 생성자 함수를 설정하고 있다. 사실 base 속성은 특별한 속성이 아니다. 어떤 이름도 가능하다. 그리고 나서 [라인 12] 에서 생성자 함수를 호출하고 있다.

4. 왜 "prototype" 속성을 명시적으로 할당하는 것을 선언해주어야 하는가?
TalentedForMusic 과 TalentedForPaint 생성자 함수를 잘 살펴보자. TalentedForMusic 은 부모 생성자 함수의 prototype 속성을 할당해 주지 않았다. [라인 43 - 46] 을 살펴보자. [라인 43]에서처럼 Talent.prototype 에 추가적인 속성을 정의하는 경우, 부모 생성자 함수의 prototype 속성을 할당하지 않았던 TalentedForMusic 의 인스턴스인 hummingMan 오브젝트에는 이 속성이 추가되지 않는다.

5. "객체 생성자 함수에서 속성" vs "object.prorotype.property = value"
Talent의 "name" 속성과 "grade" 속성을 유심히 살펴보자. "name" 속성은 생성자 함수 내부에서 선언을 했고, "grade" 속성은 Talent.prototype.grade = "none" 과 같이 prototype 의 속성으로 선언을 했다. 이것은 주요한 차이가 있다. [라인 32 - 43] 에서와 같이 name 속성에 새로운 값을 할당하더라도, 그 인스턴스의 값은 변하지 않는다. 하지만, prototype 의 속성으로 선언되는 경우 [라인 46 - 48] 에서 볼수 있듯이, 새로운 값을 할당하는 경우 그 오브젝트의 인스턴스들의 값들이 모두 변하는 것을 알 수 있다.

6. instanceof, __proto__
[라인 38] 에서과 같이 instanceof 을 통해서 어떤 오브젝트의 인스턴스인지 알 수 있다.
자바스크립의 Object을 제외한 모든 오브젝트는 __proto__ 라는 특별한 속성을 가지고 있다. (자바스크립의 모든 함수는 prototype 이라는 특별한 속성을 가지고 있다.) 이 속성은 오브젝트가 생성될 때 생성자 함수의 prototype 이 할당된다. [라인 39 - 41]에서 볼 수 있듯이 오브젝트의 __proto__ 속성과 생성자 함수의 prototype 속성이 동일함을 알 수 있다.

7. 오브젝트 생성자 함수에서의  글로벌 변수 사용
오브젝트의 생성자 함수에서 글로벌 변수를 사용을 할 때는 주의를 하여야 한다. [라인 35]에서 count가 1일 것을 기대했을 수도 있지만 사실 결과는 3이다. [라인 32], [라인 29], [라인 17]에서 호출되기 때문이다. 즉, prototype 을 할당할 때도 호출된다. 


8. 자바스크립트는 다중 상속을 지원하지 않는다.
TalentForMusic 생성자 함수에서 Talent 와 Personality 두 오브젝트를 생성하는 것처럼 보인다. 실제로  Personality 의 속성을 TalentForMusic 에서 사용할 수 있다. 하지만, [라인 35]에서 보는 것처럼 Personality에 새로운 속성을 추가하는 경우, TalentForMusic 에는 추가되지 않는 것을 알 수 있다.


9. 참조
- MDN - https://developer.mozilla.org/en/docs/Web/JavaScript
- Jasmine - http://jasmine.github.io/2.3/introduction.html

2015년 7월 4일 토요일

angularjs unittest

0. prepare project for unitest
We need angular-mocks.js. You can download it from http://angularjs.org and https://code.angularjs.org/1.4.1/. I recommend to read the post before following this post if you are not familiar with angularjs and nodejs.

$ tree angularjs-unittest/
|____
| |____angular-animate.js
| |____angular-mocks.js
| |____angular-route.js
| |____angular-sanitize.js
| |____angular-touch.js
| |____angular.js
| |____bootstrap-theme.css
| |____bootstrap.css

1. configure Karma test-runner
You should configure karma per each project respectively . You can see the following questions.
$ karma init karma.config.js

karma.config.js is created.
|____angular-animate.js
|____angular-mocks.js
|____angular-route.js
|____angular-sanitize.js
|____angular-touch.js
|____angular.js
|____bootstrap-theme.css
|____bootstrap.css
|____karma.config.js

2. create unit test file in tests
|____angular-animate.js
|____angular-mocks.js
|____angular-route.js
|____angular-sanitize.js
|____angular-touch.js
|____angular.js
|____bootstrap-theme.css
|____bootstrap.css
|____karma.config.js
|____tests
| |____hellotest.js

3. start karma
$ karma start karma.config.js








We used jasmine testing framework. You may noticed that second test case is failed. Whenever you make changes, Karma automatically detect changes and run all unit test.

2015년 7월 2일 목요일

angularjs development environment

0. description
command : need to type command  from shell
files : represent source files or related files in specific location

1. install node.js
You can install node.js from https://nodejs.org/.

2. install connect, serve-static
$ npm install connect
$ npm install serve-static

3. create server.js
make nodejs dir(any directory is ok). Refer following directory structure which i used.
|____
| |____angularjs
| | |____angular-animate.js
| | |____angular-mocks.js
| | |____angular-route.js
| | |____angular-sanitize.js
| | |____angular-touch.js
| | |____angular.js
| | |____bootstrap-theme.css
| | |____bootstrap.css
| | |____test.html
| |____nodejs
| | |____server.js

The important thing is the line 4. You should set correct path which contains angularjs app.
nodejs/server.js
4. install karma
$ npm install -g karma

5. download AngularJS
https://www.angularjs.org/

6. make angularjs directory and copy files. The directory should be set from server.js
angularjs/angular-animate.js
angularjs/angular-mocks.js
angularjs/angular-route.js
angularjs/angular-sanitize.js
angularjs/angular-touch.js
angularjs/angular.js

7. download bootstrap
http://getbootstrap.com/
copy css file to angularjs directory
angularjs/bootstrap-theme.css
angularjs/bootstrap.css

8. create test.html file in angularjs directory
angularjs/test.html

9. move to nodejs directory and run following command
$ node server.js

10. open browser and go to http//localhost:5000/test.html