CuriousY A world with wonder

`.gitignore` not work

| Comment

Problem

提交代码到别人的git repository,发现原先的代码没有.gitignore文件,很多log文件和编译文件都被提交到了repo上。于是我新建了一个.gitignore文件,但需要手动删除掉所有多出来的文件再提交一个commit(也就是说.gitignore只对之后提交的文件具有ignore作用,对已经提交的文件是不管的,即使已经提交的文件被列为了ignore,仍然会被track)。

问题是怎样能让gitignore对已提交的文件也起作用?

Solution

解决方案其实很简单,即把所有多出来的文件都删掉,再提交一个commit即可,之后这些文件即使再产生也都不会被track了。

当然手动一个一个删很麻烦,可以使用以下的命令批量删除:

git rm . -r --cached

Easter egg

有时候一个文件被gitignore了,而你想知道是哪条规则导致它被ignore的,从而去修改相应的规则,可以使用如下命令(旧版本的git可能没有这个命令):

git check-ignore -v filename

注意上面的filename最好是相对项目根目录的全路径,这样如果是因为某个文件夹整体被ignore了也可以知道,比如:pyvmomi-master/vshpereAut/vsphere_helper.pyc

Reference

  1. .gitignore is not working
  2. which gitignore rule is ignoring my file

关于Javascript中this的一点思考

| Comment

问:

下面代码中的this指代的是哪个对象?

$(document).ready(function(){
    $(".TestCase").click(function (){
      	console.log(this.id);
    });
});

答案是不确定。如果这里的$是jQuery中的那个变量名,那么this指代的是$(".TestCase")所选择的对象,否则this可能是任意对象。

好吧,我承认上面的回答有点tricky,但我主要想表达的是JavaScript里面的this的绑定是非常灵活的(关于this绑定的规则可查看Reading <this & Object Prototypes> - 1)。

实现1

比如以上的this绑定为前面选择的对象可以这样实现(selectedTarget表示上面的$(".TestCase")):

var selectedTarget = {
    id: 'the_id',
    click: function (callback) {
        this._click_callback = callback;
    },
    clickEvent: function () {
        this._click_callback();
    }
};

selectedTarget.click(function (){
    console.log(this.id);
});

首先,click函数作为selectedTarget对象的一个属性,在其被调用时(即selectedTarget.click(response);),click函数中的this表示的是调用它的对象,即selectedTarget。这里click函数的输入为另一个函数,它会在发生click的事件(这里用selectedTarget.clickEvent来代表这个事件接口)时被调用。所以click函数的作用就是绑定了click事件和它对应的回调函数(这里的绑定类似于this._click_callback = callback;)。而click的输入的函数中的this其实也是指向了selectedTarget,因为它被调用时是这一句this._click_callback();,已经是作为selectedTarget的属性被调用了。

实现2

换个思路,可以使用bind函数来显示地绑定this到目标对象:

var selectedTarget = {
    id: 'the_id',
};

function bindClickFunc(callback) {
    this._click_callback = callback;
}

function callClickFunc() {
    this._click_callback();
}

selectedTarget.click = bindClickFunc.bind(selectedTarget);
selectedTarget.clickEvent = callClickFunc.bind(selectedTarget);

selectedTarget.click(function (){
    console.log(this.id);
});

使用bind的好处是this指向的对象被显式表达出来了,代码更容易理解。

实现3

以上实现都是把this指向了调用者,这里让this指向一个无关的对象:

var selectedTarget = {
    id: 'the_id',
};

function bindClickFunc(callback) {
    this._click_callback = callback;
}

function callClickFunc() {
    this._click_callback();
}

var anotherObj = {};
selectedTarget.click = bindClickFunc.bind(anotherObj);
selectedTarget.clickEvent = callClickFunc.bind(anotherObj);

selectedTarget.click(function (){
    console.log(this.id);
});

结论

关于JavaScript里面的this到底指向哪个对象,由于其规则非常灵活且被封装后也无法轻易得知它的指向(可以理解为它就是run-time动态的),所以大部分使用的时候只要按照约定俗成的方式去知道这里的this是哪个对象即可(约定俗成是被调用函数的所属对象和this绑定,即隐式绑定的结果),至于到具体实现才需要考虑怎样绑定this来达到约定俗成的效果,这时候就需要根据它的几个规则来逐一判断了。

Reading <Types & Grammar> - 1

| Comment

Chapter 1: Types

Bah! We’re going to use this rough definition (the same one that seems to drive the wording of the spec): a type is an intrinsic, built-in set of characteristics that uniquely identifies the behavior of a particular value and distinguishes it from other values, both to the engine and to the developer.


Armed with a full understanding of JavaScript types, we’re aiming to illustrate why coercion’s bad reputation is largely overhyped and somewhat undeserved – to flip your perspective, to seeing coercion’s power and usefulness.

We’ll see.


If you want to test for a null value using its type, you need a compound condition:

var a = null;

(!a && typeof a === "object"); // true

null is the only primitive value that is “falsy” but that also returns "object" from the typeof check.


It’s tempting for most developers to think of the word “undefined” and think of it as a synonym for “undeclared.” However, in JS, these two concepts are quite different.

An “undefined” variable is one that has been declared in the accessible scope, but at the moment has no other value in it. By contrast, an “undeclared” variable is one that has not been formally declared in the accessible scope.

Consider:

var a;

a; // undefined
b; // ReferenceError: b is not defined

Error message返回”b is not declared”更准确。


There’s also a special behavior associated with typeof as it relates to undeclared variables that even further reinforces the confusion. Consider:

var a;

typeof a; // "undefined"

typeof b; // "undefined"

The typeof operator returns "undefined" even for “undeclared” (or “not defined”) variables.

可以用typeof来检查一个变量是否被声明了(难道没有try..catch么)。


Another way of doing these checks against global variables but without the safety guard feature of typeof is to observe that all global variables are also properties of the global object, which in the browser is basically the windowobject. So, the above checks could have been done (quite safely) as:

if (window.DEBUG) {
    // ..
}

if (!window.atob) {
    // ..
}

Unlike referencing undeclared variables, there is no ReferenceError thrown if you try to access an object property (even on the global window object) that doesn’t exist.

检查是否被声明的另一个思路,但只能对全局变量有用。

Read more

Python打包工具setuptools的一点经验

| Comment

比较早接触到setuptools是在写pytest的plugin时,研究了一下pytest是如何通过setuptools中设置的名为pytest11entry_points来加载pip install的pytest plugin的。后来偶然间研究一些cmdline的库时,发现通过名为console_scriptsentry_points可以非常方便地把某个python函数注册到环境变量PATH中对应的一个可执行文件中,而不需要自己写setup脚本来做这件事情了。顿时觉得setuptools好强大。

关于怎么使用setuptools,可以参考官方文档或一些开源的cmdline工具(比如virtualenv)。以下,仅记录我使用setuptools库的一些经验(目前还不是很丰富。。):

  1. 使用python setup.py sdist 命令来在当前目录下生成打包好的文件,方便检查是否所有需要打包的文件都被打包了。

  2. 使用 python setup.py install 命令来把打包好的package安装到当前Python环境中,方便在布之前先在本地安装进行测试。

  3. 如果需要打包的文件包含非Python package文件(比如一些资源文件),则需要在setup.py同级目录下新建一个MANIFEST.in文件,在其中包含需要额外打包的文件,比如:

    recursive-include splunk_env_switcher/ansible_playbooks *.yml *.py
    include splunk_env_switcher/ansible.cfg
    

    并且,在setup.py中的setuptools.setup方法中添加include_package_data=True的参数。

  4. 使用以下命令可以根据当前目录下的setup.py打包发布到指定的pypi服务器:

    sudo python setup.py sdist upload -r https://specified-pypi-server
    
  5. 一些有用的entry_points

    • console_scripts: 绑定指定的package中的函数到某个环境变量(作为cmdline工具),比如:

      entry_points={
          'console_scripts': ['virtualenv=virtualenv:main'],
      }
      
    • pytest11: pytest官方定义的entry_point,用来识别通过pip install的pytest plugin,比如:

      entry_points={
          'pytest11': [
              'xdist = xdist.plugin',
              'xdist.looponfail = xdist.looponfail',
              'xdist.boxed = xdist.boxed',
          ],
      }
      

How to force browser to reload cached CSS/JS files

| Comment

Problem

在已运行的web server上更新了一个css文件,结果在用户端由于缓存的缘故,该css文件并没有被更新,反复刷新页面也没有用,只有清除掉缓存再打开网页才成功加载了新的css文件。问题是能否从服务端入手,迫使客户端来加载更新的资源文件?

Solution

解决方法是用stackoverflow上提到的一个方案:

在页面的资源加载语句中在资源文件后加上?以及一个版本号。即:

<script type="text/javascript" src="myfile.js?$$REVISION$$"></script>

实验了下确实可行。

答案中还提到这种给资源添加版本号的行为是可以持续集成到代码提交时自动执行的(判断资源文件改变了再修改版本号),有空可以再研究下web开发的CI。

此外,值得一提的是,这个方法有一个小缺点,即会占用更多客户端的缓存空间:

For awareness: this is considered to be a hack. This method tricks the browser into thinking that a new file is being specified, as it simply looks at the full file name without interpreting it. foo.js?1 is not the same name as foo.js?2, so the browser will think they are two different files. One downside is that both files will simultaneously exist in the users’ cache, taking up unnecessary space.

Easter egg

对于客户端而言,要强制加载最新的js/css文件其实有更便捷的方法(不用手动清除缓存)。

对Windows:CTRL+F5

对MacOS:Command+Shift+R

Reference

| Page 16 of 25 |