差沙的密碼 -- SSHWSFC's code
閱讀本Blog請自備塑料袋一只 |
經(jīng)過兩天的努力,終于在Android上面跑起來MSN了。現(xiàn)在實(shí)現(xiàn)了基本的聊天功能,打算陸續(xù)的把其他功能完善,萬事開頭難,相信以后的工作會很順利。
Gtalk的功能由于有官方支持,早就弄了跟這個(gè)差不多的版本。
另外,這個(gè)軟件目前是以插件的形式開發(fā),多一個(gè)協(xié)議就是多一個(gè)apk,實(shí)現(xiàn)一些intent即可。官方的IM包里面有很多支持,可惜文檔沒有提及。
今天看到Air1.0和Ext2.0.2的發(fā)布消息,很是興奮,要知道Ext的每個(gè)版本升級都是很實(shí)惠的。
Ext2.0.2的這次升級主要是針對Air的支持,看來他們的關(guān)系是越來越近了,我也借機(jī)小試了一下Air。
簡單說說Air的開發(fā)過程:
1.先要下載jre 和 airSDK
2.jre就不說了,airSDK也是簡單的解壓一下便可。
可以看看SDK下面的bin目錄,一共倆文件,一個(gè)adl一個(gè)adt,adl是用來測試的,adt使用編輯發(fā)布的(ADT怎么讓我想起來android了)
3.創(chuàng)建一個(gè)普通的目錄作為項(xiàng)目目錄。OK,可以寫頁面了。就是寫html js flash什么的,都可。
4.編寫一個(gè)xml文件,名字不限。內(nèi)容嘛~~~~
看看這個(gè)文件,airSDK\templates\descriptor-template.xml 里面有詳細(xì)的解釋,拿過來改改即可,給一個(gè)例子:
<?xml version="1.0" encoding="UTF-8"?> <application xmlns="http://ns.adobe.com/air/application/1.0.M6"> <id>examples.html.HelloWorld</id> <version>0.1</version> <filename>HelloWorld</filename> <initialWindow> <content>HelloWorld.html</content> <visible>true</visible> <width>400</width> <height>200</height> </initialWindow> </application>
5.運(yùn)行airSDK\bin\adl.exe (那個(gè)創(chuàng)建的xml文件名),運(yùn)行即可。
PS:我一般用eclipse來編輯,用外部命令的工具來運(yùn)行adl,很方便。
簡單的說了一下Air的開發(fā)方法后,我們來簡單的看一下Ext都對Air提供了什么支持。
1.Ext.air.FileProvider
Ext提供狀態(tài)保存的功能,在對AIr的支持中Ext實(shí)現(xiàn)了一個(gè)Provider,這個(gè)Provider把狀態(tài)保存在本地目錄的一個(gè)文件里。使用方法如下:
// Initialize the state provider Ext.state.Manager.setProvider(new Ext.air.FileProvider({ file: 'ext.state', // if first time running defaultState : { mainWindow : { width:400, height:200, x:10, y:10 } } }));
制定Provider為Ext.air.FileProvider即可,這個(gè)操作一般在onReady里面執(zhí)行。當(dāng)然需要你先創(chuàng)建一個(gè)ext.state文本文件,在程序根目錄下即可。這樣ext的應(yīng)用運(yùn)行時(shí),窗口等大小的調(diào)整,位置之類的調(diào)整都能保存下來了。很方便。
這里包裝的Air代碼主要是:
air.File.applicationStorageDirectory.resolvePath
air.FileStream
等
2.Ext.air.NativeWindow
Ext可以調(diào)用Air實(shí)現(xiàn)Native的窗口。使用方法如下:
var win = new Ext.air.NativeWindow({ id: 'mainWindow', instance: window.nativeWindow, minimizeToTray: true, trayIcon: 'ext-air/resources/icons/extlogo16.png', trayTip: 'Simple Tasks', trayMenu : [{ text: 'Open Simple Tasks', handler: function(){ win.activate(); } }, '-', { text: 'Exit', handler: function(){ air.NativeApplication.nativeApplication.exit(); } }] });
我們可以看到,其中最吸引人的是系統(tǒng)托盤的功能,可以方便的指定系統(tǒng)托盤的各種屬性。
這里包裝的主要是:
window.runtime.flash.html.HTMLLoader.createRootWindow
air.Screen.mainScreen.visibleBounds
3.Ext.sql.Connection
這個(gè)是重頭戲,對db的支持,我們知道Air的DB是采用sqlite3來實(shí)現(xiàn)的。Ext封裝了Air的db操作,簡化統(tǒng)一了一些,而且提供了Store的支持,非常強(qiáng)大:
讓我們簡單看一下用法:
首先取得connection
var conn = Ext.sql.Connection.getInstance();
而后打開db
conn.open('ext.db');//這里的文件如果不存在會自動創(chuàng)建
創(chuàng)建Table
conn.createTable({ name: 'user', key: 'userId', fields: [ {name: 'userId', type:'string'}, {name: 'name', type:'string'}, {name: 'pwd', type:'string'}, {name: 'email', type:'string'} ] });
取得一個(gè)Table
var userDao = conn.getTable('user','userId');
查詢
var users = userDao.select();//這里可以寫條件式
添加
var newuser = { userId : 'sshw', name : 'sshwsfc', pwd : 'test', email : 'sshwsfc@gmail.com' } userDao.insert(newuser);
感覺使用上還是蠻不錯(cuò)的,大家可以一點(diǎn)點(diǎn)試試看。
值得一提的是,在源碼中發(fā)現(xiàn)Connection這里設(shè)計(jì)成了工廠的模式,Connection是一個(gè)偽接口,實(shí)現(xiàn)除了Air的還有GoogleGear的,會根據(jù)所處環(huán)境選擇,灰常的好。
功能還在研究中,有心得了一點(diǎn)點(diǎn)給大家分享,
PS:打算搞一個(gè)iphone的信息管理軟件練練手。反正都是sqlite的
在朋友和同事的極力推薦下最近開始看上了python,其實(shí)主要是還是因?yàn)閜ython是2007年度語言,怎么的也要與時(shí)俱進(jìn)呀.最近一路看來有些心得,希望能與大家分享,小弟其實(shí)也只接觸不到一周的python,有說錯(cuò)的地方還望大家指出改正.
不打算從py的語法基礎(chǔ)說起了,直接說說對django的心得:
接觸django首先需要了解可能就是他那個(gè)model,建立一個(gè)model就什么都有了,這對于搞java得人員來說還是挺有吸引力的(當(dāng)然貌似對于動態(tài)語言這都是小兒科),那么讓我們先看一個(gè)model的例子:
偷懶了,直接拿django-admin里面的User出來了
class User(models.Model): username = models.CharField(_('username'), maxlength=30, unique=True, validator_list=[validators.isAlphaNumeric])) first_name = models.CharField(_('first name'), maxlength=30, blank=True) last_name = models.CharField(_('last name'), maxlength=30, blank=True) email = models.EmailField(_('e-mail address'), blank=True) password = models.CharField(_('password'), maxlength=128)) class Meta: ordering = ('username',)
每個(gè)屬性就是一個(gè)庫表的字段,定義起來非常簡單明了,models里面提供了很多種類的Field類似上面的EmailField。不同的Field有不同的設(shè)置,可以看相應(yīng)的原來來了解相關(guān)的設(shè)置.
在model class內(nèi)部還有一個(gè)class Meta,這個(gè)Class的屬性制定了這個(gè)表的一些存取策略,例如這里的ordering。MetaClass里面的屬性可以用model的_meta屬性取得。OK,那么這樣一個(gè)model怎么就能實(shí)現(xiàn)對數(shù)據(jù)庫表的靈活操作了呢。讓我們來看看吧。
首先先分析一下/django/django/db/models/base.py這個(gè)文件,其中包含了models.Model這類的定義:
看看class定義的第一行吧,第一行就夠我琢磨一陣子的了:
class Model(object): __metaclass__ = ModelBase
Model采用了new style class定義,關(guān)于這個(gè)內(nèi)容大家可以放狗看一下,第一行是一個(gè)__metaclass__屬性的定義,該屬性的值是ModelBase,這是一個(gè)類。__metaclass__的意思是,指定一個(gè)class,這個(gè)class的實(shí)例就是本class,相信您已經(jīng)暈了。那么就拿這個(gè)Model的例子來說明一下,如果沒有__metaclass__這個(gè)屬性,產(chǎn)生一個(gè)實(shí)例就是正常的流程,有了這個(gè)屬性流程會有改變:
首先調(diào)用BaseModel.__new__(cls, name, bases, attrs)這個(gè)方法,回返回的值是一個(gè)class類型,然后用這個(gè)class來創(chuàng)建實(shí)例。其實(shí)BaseModel就是Model的元類,來制定Model這個(gè)類的最終樣子。關(guān)于元類的更多信息請看這里
那么我們的目光一下轉(zhuǎn)移到BaseModel這個(gè)類上,我有種直覺,Meta這個(gè)class最后可以用_meta來取就是在這里做的手腳,看一下BaseModel的定義吧,有點(diǎn)長:
class ModelBase(type): "Metaclass for all models" def __new__(cls, name, bases, attrs): # If this isn't a subclass of Model, don't do anything special.
if name == 'Model' or not filter(lambda b: issubclass(b, Model), bases): #1 return super(ModelBase, cls).__new__(cls, name, bases, attrs) # Create the class.
new_class = type.__new__(cls, name, bases, {'__module__': attrs.pop('__module__')}) #2
new_class.add_to_class('_meta', Options(attrs.pop('Meta', None))) #3
new_class.add_to_class('DoesNotExist', types.ClassType('DoesNotExist', (ObjectDoesNotExist,), {})) # Build complete list of parents #4 for base in bases: # TODO: Checking for the presence of '_meta' is hackish. if '_meta' in dir(base): new_class._meta.parents.append(base) new_class._meta.parents.extend(base._meta.parents) model_module = sys.modules[new_class.__module__] if getattr(new_class._meta, 'app_label', None) is None: # Figure out the app_label by looking one level up. # For 'django.contrib.sites.models', this would be 'sites'. new_class._meta.app_label = model_module.__name__.split('.')[-2] #5 # Bail out early if we have already created this class. m = get_model(new_class._meta.app_label, name, False) #6 if m is not None: return m # Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj) #7 # Add Fields inherited from parents for parent in new_class._meta.parents: for field in parent._meta.fields: # Only add parent fields if they aren't defined for this class. try: new_class._meta.get_field(field.name) except FieldDoesNotExist: field.contribute_to_class(new_class, field.name) #8 new_class._prepare() register_models(new_class._meta.app_label, new_class) #9 # Because of the way imports happen (recursively), we may or may not be # the first class for this model to register with the framework. There # should only be one class for each model, so we must always return the # registered version. return get_model(new_class._meta.app_label, name, False) #10
簡單分析一下這個(gè)代碼:
1. 檢查class是否為Model的子類,不是的話,不做任何處理,直接傳給父類處理,也就相當(dāng)于正常的處理了class,注意super在多重繼承的時(shí)候應(yīng)該嚴(yán)格使用
2. 用type來創(chuàng)建類,創(chuàng)建的就是正常的ModelClass
3. 這句很重要,add_to_class是Model里面的class方法,這個(gè)方法其實(shí)就是傳入name和value,給Model添加class屬性.看到了,原來神奇的_meta就是這么來的. 提到add_to_class方法,簡單看一下它的代碼:
def add_to_class(cls, name, value): if name == 'Admin': assert type(value) == types.ClassType, "%r attribute of %s model must be a class, not a %s object" % (name, cls.__name__, type(value)) value = AdminOptions(**dict([(k, v) for k, v in value.__dict__.items() if not k.startswith('_')])) if hasattr(value, 'contribute_to_class'): value.contribute_to_class(cls, name) else: setattr(cls, name, value) add_to_class = classmethod(add_to_class)
4. Meta的集成,Option的這個(gè)類提供繼承方法
5. 取得applabel,就是把model的名字分割取到數(shù)第二個(gè),我很喜歡-2這樣的設(shè)定
6. get_model方法取得緩存里面的東西。
7. 把所有的class attr拿出來搞一遍,一般的屬性就setattr弄回去了,要是這個(gè)屬性有contribute_to_class這個(gè)callable屬性,那就執(zhí)行之(Admin的處理完全也可以這樣,其實(shí)我們常用的objects就是用這個(gè)方法弄的)
8. 每個(gè)Field調(diào)用自己的contribute_to_class方法來進(jìn)行特殊的處理
9. 進(jìn)入緩存,,暫且叫緩存吧,里面的東西大家看看很簡單 文件在 /django/django/db/models/loading.py 里面還是有很多內(nèi)容的
10.看注釋說的很清楚了,我們一定要在緩存里面拿model。
其中需要指出的是,new_class._prepare() 這個(gè)方法,簡單列出片段:
def _prepare(cls):
# Creates some methods once self._meta has been populated.
opts = cls._meta
opts._prepare(cls)
....
dispatcher.send(signal=signals.class_prepared, sender=cls)
中間省略了一些代碼,不是我沒看懂的就是沒意思的,關(guān)鍵要看這個(gè)dispatcher呀。這里是監(jiān)聽者模式,dispatcher.send(signal=signals.class_prepared, sender=cls)放松了一個(gè)包含特定信號的事件,讓監(jiān)聽的人可以做相應(yīng)的處理。這樣的信號還有很多種,我們可以很簡單的截獲信號,處理相應(yīng)的內(nèi)容。也許您還記得,在我們創(chuàng)建db的時(shí)候,會提示創(chuàng)建一個(gè)超級用戶,其實(shí)就是用這個(gè)方法來弄的。
那我為什么要把這個(gè)單獨(dú)拿出來說呢,因?yàn)楸O(jiān)聽這個(gè)事件的人不是別人,是"objects"!!!在文件/django/django/db/models/manager.py的開頭就有這樣的代碼:
def ensure_default_manager(sender): cls = sender if not hasattr(cls, '_default_manager'): # Create the default manager, if needed. try: cls._meta.get_field('objects') raise ValueError, "Model %s must specify a custom Manager, because it has a field named 'objects'" % cls.__name__ except FieldDoesNotExist: pass cls.add_to_class('objects', Manager()) dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
定義了一個(gè)callable,然后監(jiān)聽signals.class_prepared信號,呵呵,連上了吧,只要Class準(zhǔn)備好了,就調(diào)用這個(gè)方法。簡單判斷有沒有_default_manager'屬性和meta里面的objects后,開始插入objects。cls.add_to_class('objects', Manager()) 很熟悉吧,前面講過不多說了。
PS:寫到這里不由得感嘆,為啥同樣是往Class里面加入東東,要搞這么多的花樣呢,我以前也寫過一個(gè)Rails配置加載過程的分析文檔,雖然一個(gè)簡單的加載配置就把所有動態(tài)語言玩?zhèn)€遍,但是這也太不規(guī)范了吧,可能不這么玩就不算“動態(tài)”語言了吧,哈哈。
終于Model的Class造好了,相信大家以后造自己的Class也能玩出更多的花樣。那么可以開始下一步了。我到老家后再寫吧,打算講講神奇的objects,也就是Manager,其實(shí)就是玩QuerySet。。那里有很多的__xxx__方法,很好很強(qiáng)大
2007年11月12日(北美時(shí)間), Android的APP SDK公布, 開始了google手機(jī)的開發(fā)大賽. 我們致力于Android的開發(fā)文檔翻譯, 開發(fā)技術(shù)交流等工作, 希望為Android平臺在中國的推廣貢獻(xiàn)自己的力量.
ProcessInstance里面有一個(gè)findToken(String tokenPath)方法。這里面寫的是tokenPath。 tokenPath跟文件系統(tǒng)的規(guī)則差不多。類似 /fork1/fork2 這樣的。
那么,怎么到fork2下的一個(gè)分支token ?
token自己也有findToken這個(gè)方法,不同的是ProcessInstance的是以rootToken為起點(diǎn),token自己的是以自己為起點(diǎn)。那么取到token2下面的分支
token2.findToken("token")
如果有返回token,沒有返回null
至于token的名字,我剛才查源碼才發(fā)現(xiàn),只有在Fork節(jié)點(diǎn)才會給token賦予名字。。。
那么token2.findToken("token") 這里"token"那里來
命名的規(guī)則,如下。。
這里"token"那里來?這個(gè)token名字,你自己可以根據(jù)命名規(guī)則得到 。看到這里應(yīng)該很明了了
token的命名規(guī)則;首先根據(jù)transitionName的名字命名,這個(gè)transitionName的名字是你自己的寫的你不可能不知道。 如果transitionName的名字重名了,加自然數(shù)區(qū)分 當(dāng)然,如果transitionName沒有名字,用分支的個(gè)數(shù)+1作為名字。
應(yīng)該比較清楚了。
PS:這個(gè)是qq聊天記錄的整理版,所以說話比較詭異。為的是記錄下來避免忘記,也感謝群里的朋友。發(fā)現(xiàn)互相解決問題是提高水平的一個(gè)捷徑。。
說ruby是怪異的語法有點(diǎn)不妥當(dāng),動態(tài)語言里面不乏這樣的語法出現(xiàn)。但是看了一些源碼后發(fā)現(xiàn),使用ruby的用法真的各有不同,就像大家以前說的,ruby每個(gè)人寫出來的可能都不同。
現(xiàn)來說Rails里面如何加載config的吧。
在java里面config絕對是一個(gè)resource文件,然后通過讀取配置的工具加入進(jìn)來,在分析處理。
在ROR里面完全不是這么回事。
1.首先大家要了解的是,在我們啟動 ruby script/server 的時(shí)候,rails做了一系列的處理,最后他執(zhí)行了environment.rb
這里的config其實(shí)是Initializer內(nèi)部的一個(gè)變量,掌控全局的配置信息,我們可以使用這個(gè)config來配置我們想要的。Rails::Initializer.run的源碼是這樣的,yield再一次顯示了他的威力,讓我們在配置文件中得以配置config。然后實(shí)例化了一個(gè)initializer?之后,把config作為參數(shù)傳入了。
我們接著往下走,可以看到initializer?做了一系列的初始化工作,包括load_path的設(shè)定,路由的初始化,和activerecord的初始化。我們關(guān)心的還是配置如何起作用,那么來看看environments目錄下面的配置文件是如何導(dǎo)入的吧。
IO.read(configuration.environment_path) ,,這里就不使用什么回調(diào)不回調(diào)了,而是干脆IO拿出來eval一把,這里也是吃了一驚,這樣也可以呀~~~~~~~然后,我們可以看看,他處理常量的方法,把自己配置文件中的常量全部放入Object里面,起到全局常量的目的。
最絕的還是initialize_framework_settings,使用了有一個(gè)ruby的技巧。
configuration.frameworks里面存放的是rails個(gè)個(gè)組件的名字,比方說active_record之類。然后把這個(gè)名字大寫轉(zhuǎn)換,然后用constantize取得ActiveRecord這個(gè)Module(注意,這些東西都在activesupport里面呢,activesupport/lib/active_support/core_ext/string/inflections.rb )。然后用const_get取得這個(gè)模塊的Base類,也就是ActiveRecord::Base這個(gè)類了(下面都叫做Base類),所有的Rails的組件都是這個(gè)命名規(guī)則改天我們自己想要做一個(gè)Rails的組件加進(jìn)來,也可以這樣(但是要稍微修改一個(gè)源碼)。
然后,我們吧config里面的內(nèi)容給Base類。configuration.send(framework)是調(diào)用一個(gè)組件名稱的方法,比方說active_record,就是去的config里面的active_record屬性(這是最基本的),通過后面的do我們可以看到config返回的是一個(gè)hash,然后把hash中每一個(gè)key作為變量,value為傳入值,傳入Base類。。。這里大家應(yīng)該沒什么問題了,看看我們的config文件是怎么寫的吧。
哦,看著很暈吧,config就是我們的配置對象,按照我們上面的說法,config.action_view之類framework的變量應(yīng)該是一個(gè)hash才對呀,如果是hash的話,不應(yīng)該用這樣的方式傳入,可能會用 config.action_view = {:debug_rjs => true}來傳入。
OK.我們來看這個(gè)變量到底是什么樣的hash。
在初始化這些變量的時(shí)候,Rails給他賦值為OrderedOptions.new。這個(gè)特殊的類型可能就是關(guān)鍵。
看到其中的玄妙了么,method_missing~~~!! 如果調(diào)用一個(gè)**=的方法 ,就像當(dāng)用傳入一個(gè)HASH的值,key就是方法的名字。
也就是:config.action_view.debug_rjs??=?true?相當(dāng)于config.action_view[:debug_rjs] = true
OK ,大體上描述了一下,可以看到簡單的一個(gè)Rails初始化已經(jīng)給我們展示了幾乎全部ruby的靚麗之處,這能說明,這個(gè)亮點(diǎn)肯定是貫穿rails的基本,在以后的深入研究中我們就能看到了。
為了記錄自己看Rails源碼的過程,全程記錄無廢話。
我們看看script/server都干了什么
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 | |||
4 | 5 | 6 | 7 | 8 | 9 | 10 | |||
11 | 12 | 13 | 14 | 15 | 16 | 17 | |||
18 | 19 | 20 | 21 | 22 | 23 | 24 | |||
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
1 | 2 | 3 | 4 | 5 | 6 | 7 |