Jin: И снова о наследовании
Зацените крутую либу реализующую новый подход к организации кода)
Фичи: 1. множественное виртуальное наследование 2. прямой быстрый доступ к любому методу предка 3. автоматическое объявление классов и пространств имён 4. объявление методов и примешивание в произвольном порядке 5. автоматическое выявление конфликтов на уровне методов 6. типизированные свойства 7. глобально именуемые функции Объявим простенький синглтон:
$jin.method( function URI_encode( text ){
return encodeURIComponent( text )
})
$jin.method( function URI_decode( text ){
return decodeURIComponent( text )
})
Данный код примерно эквивалентен следующему:
var URI = URI || {}
URI.encode = function URI_encode( text ){
return encodeURIComponent( text )
}
URI.decode = function URI_decode( text ){
return decodeURIComponent( text )
}
Как видно, мы избавились от необходимости дублировать имя функции при объявлении (что полезно при дебаге, но зачастую лениво), а также не беспокоимся о том, чтобы нужный неймспейс существовал до объявления методов. Символ подчёркивания, как видно, заменяется на точку. Кроме того двойное подчёркивание заменяется на ".prototype.", что будет продемонстрировано ниже. Теперь создадим простейший класс: $jin.mixin( '$jin_klass', 'Man' ) $jin.property( 'Man__name', String ) Тут мы примешали к пространству имён Man поведение "$jin_klass", что превращает "Man" в фабрику объектов. После чего определяем свойство "name", которое всегда является строкой. Инстанцирование происходит простым вызовом: var Anonymous = Man() При этом можно передать хэш со значениями свойств:
var John = Man({ name: 'John' })
Попытка передать значение для несуществующего свойства приведёт к ошибке, так как соответствующая функция не будет найдена.
Man({ age: 17 }) // Error!
Свойства - всего-лишь функции, которые в зависимости от числа переданных параметров либо возвращают своё значение, либо устанавливают. Man().name( 'Bob' ).name() // 'Bob' При установке значения переданный параметр прогоняется через "типа свойства" - функцию, которую мы передали вторым параметром при создании свойства. Man().name( 17 ).name() // '17' потому что String( 17 ) Если значение ещё не установлено, то функция типа вызывается без параметров, чтобы сгенерировать дефолтное значение. Man().name() // '' потому что String() Разумеется можно определять различные свои типы. Наследование реализуется через примешивание: $jin.property( 'Artist__sceneName', String ) $jin.mixin( '$jin_klass', 'Artist', 'Man' ) Man().sceneName() // '' Примешивать и создавать методы можно опять же в произвольном порядке. $jin.mixin( 'Artist', '$jin_klass', 'Man' ) $jin.property( 'Artist__pseudoName', String ) Man().sceneName() // '' Чтобы каждый раз не примешивать $jin_class можно сразу его и вызывать: $jin.class( 'Artist', 'Man' ) Иногда могут возникать конфликты имён: $jin.property( 'Artist__name', String ) $jin.klass( 'Artist', 'Man' ) $jin.property( 'Man__name', String ) Man().name() // Error! Чтобы решить его нужно явно указать, что один метод может перегружать другой, посредством добавления дополнительного параметра вначале (коих может быть и несколько): $jin.property( 'Artist__name', String ) $jin.klass( 'Artist', 'Man' ) $jin.property( 'Artist__name', 'Man__name', String ) Man().name() // '' Тут мы указали, что в случае конфликта между "Artist__name" и "Man__name" использовано будет последнее. $jin.method действует аналогично.
$jin.method( function Man__toString( ){
return 'Man'
})
$jin.method( function Black__toString( ){
return 'Black'
})
$jin.klass( 'Man', 'Black', 'ManInBlack' )
$jin.method( 'Man__toString', 'Black__toString', function ManInBlack__toString( ){
return this.Man__toString() + ' in ' + this.Black__toString()
})
ManInBlack() + '' // Man in Black
Как видно доступ к перегруженным методам возможен через их полные имена. Указание перегружаемых методов для каждого перегружающего метода может показаться избыточным, однако перегрузка на уровне классов не может выявить конфликты при появлении новых методов в них. Поэтому такая перегрузка и не предусмотрена. Багрепорты и идеи приветствуются) |
Забыл саму либу)
this.$jin = {}
$jin.value = function $jin_value( value ){
var func = function $jin_value_instance( ){
return func.$jin_value
}
func.$jin_value = value
return func
}
$jin.root = $jin.value( this )
$jin.glob = function $jin_glob( name, value ){
var keyList = name.split( '_' )
var current = $jin.root()
var currentName = ''
while( keyList.length > 1 ){
var key = keyList.shift() || 'prototype'
currentName += ( currentName ? '_' : '' ) + ( key === 'prototype' ? '' : key )
if(!( key in current )){
current[ key ] = $jin.trait.make( currentName )
}
current = current[ key ]
}
var key = keyList.shift() || 'prototype'
if( arguments.length > 1 ){
current[ key ] = value
} else {
value = current[ key ]
}
return value
}
$jin.lazy = function $jin_lazy( generator ){
if( typeof generator === 'string' ){
generator = $jin.lazy.glob( generator )
}
var lazy = function $jin_lazy_instance( ){
return lazy.$jin_lazy_func.apply( this, arguments )
}
lazy.$jin_lazy_gen = generator
lazy.$jin_lazy_func = function $jin_lazy_generate( ){
var func = lazy.$jin_lazy_func = lazy.$jin_lazy_gen()
return func.apply( this, arguments )
}
return lazy
}
$jin.lazy.glob = function $jin_lazy_glob( name ){
var lazy = function $jin_lazy_glob( ){
return $jin.glob( lazy.$jin_lazy_name )
}
lazy.$jin_lazy_name = name
return lazy
}
$jin.trait = function $jin_trait( name ){
var trait = $jin.glob( name )
if( trait ) return trait
trait = $jin.trait.make( name )
return $jin.glob( name, trait )
}
$jin.trait.make = function $jin_trait_make( name ){
eval( 'var trait= function ' + name + '( ){ \
return ( this instanceof trait ) ? this : trait.apply( trait, arguments ) \
}' )
trait.name = name
trait.apply = void 0
trait.prototype = {}
return trait
}
$jin.method = function $jin_method( ){ // arguments: resolveName*, func
var resolveList = [].slice.call( arguments )
var func = resolveList.pop()
var name = func.name = func.name || func.toString().match( /^\s*function\s*([$\w]*)\s*\(/ )[ 1 ]
if( !name ) throw new Error( 'Can not register anonymous function' )
func.$jin_method_name = func.$jin_method_name || name
func.$jin_method_resolveList = resolveList.concat( func.$jin_method_resolveList || [] )
$jin.method.define( name, func )
}
$jin.method.define = function $jin_method_define( name, func ){
var funcName = func.$jin_method_name
if( !funcName ) throw new Error( '$jin_method_name is not defined in [' + func + ']' )
var nameList = name.split( '_' )
var methodName = nameList.pop()
var ownerPath = nameList.join( '_' )
var owner = $jin.trait( ownerPath )
owner[ funcName ]= func
var existFunc = owner[ methodName ]
checkConflict: {
if( existFunc === void 0 ) break checkConflict
if( typeof existFunc !== 'function' ){
throw new Error( 'Can not redefine [' + existFunc + '] by [' + funcName + ']' )
}
if( func === existFunc ) return existFunc
if( !existFunc.$jin_method_name ) break checkConflict
func = $jin.method.merge( existFunc, func, name )
}
owner[ methodName ]= func
var slaveList = owner.$jin_mixin_slaveList
if( slaveList ) slaveList.forEach( function( slavePath ){
$jin.method.define( slavePath + '_' + methodName, func )
})
return func
}
$jin.method.merge = function $jin_method_merge( left, right, name ){
var leftConflicts = left.$jin_method_conflictList || [ left ]
var rightConflicts = right.$jin_method_conflictList || [ right ]
var conflictList = leftConflicts.concat( rightConflicts )
var leftResolves = left.$jin_method_resolveList || []
var rightResolves = right.$jin_method_resolveList || []
var resolveList = leftResolves.concat( rightResolves )
conflictList = conflictList.filter( function( conflict ){
return !~resolveList.indexOf( conflict.$jin_method_name )
})
if( conflictList.length === 0 ){
throw new Error( 'Can not resolve conflict ' + name + ' because cyrcullar resolving' )
} else if( conflictList.length === 1 ){
var func = conflictList[0]
} else if( conflictList.length > 1 ){
eval( 'var func= function ' + name + '( ){ \
throw new Error( "Conflict in [" + func.$jin_method_name + "] by [" + func.$jin_method_conflictList + "]" )\
}' )
func.$jin_method_name = name
func.$jin_method_conflictList = conflictList
}
func.$jin_method_resolveList = resolveList
return func
}
$jin.method.naming = function $jin_method_naming( name, owner ){
if( arguments.length < 2 ){
owner = $jin.glob( name )
}
for( var key in owner ){
if( !owner.hasOwnProperty( key ) ) continue
var value = owner[ key ]
if( Object( value ) !== value ) continue
$jin.method.naming( name + '_' + key, value )
}
if( typeof owner === 'function' && !owner.$jin_method_name ){
$jin.method.naming( name + '_', owner.prototype )
owner.$jin_method_name = name
owner.$jin_method_resolveList = [ '$jin_klass__constructor' ]
}
}
$jin.mixin = function( ){ // arguments: sourceName+, targetName
var trait = $jin.mixin.object.apply( this, arguments )
for( var index = 0; index < arguments.length; ++index ){
arguments[ index ] += '_'
}
$jin.mixin.object.apply( this, arguments )
return trait
}
$jin.mixin.object = function( ){ // arguments: sourceName+, targetName
var sourcePathList = [].slice.call( arguments )
var targetPath = sourcePathList.pop()
var target = $jin.trait( targetPath )
sourcePathList.forEach( function( sourcePath ){
var source = $jin.trait( sourcePath )
source.$jin_mixin_slaveList = source.$jin_mixin_slaveList || []
if( ~source.$jin_mixin_slaveList.indexOf( targetPath ) ) return
source.$jin_mixin_slaveList.push( targetPath )
for( var key in source ){
var func = source[ key ]
if( typeof func !== 'function' ) continue
if( !func.$jin_method_name ) continue
$jin.method.define( targetPath + '_' + key, func )
}
if( source.constructor && source.constructor.$jin_method_name ){
$jin.method.define( targetPath + '_constructor', source.constructor )
}
})
return target
}
$jin.property = function $jin_property( ){ // arguments: resolveName*, name, type
var resolveList = [].slice.call( arguments )
var type = resolveList.pop()
var name = resolveList.pop()
var fieldName = '_' + name
eval( 'var property = function ' + name + '( ){ \
return property.apply( this, arguments ) \
}' )
property.name = name
property.apply = function $jin_property_apply( obj, args ){
if( args.length ){
obj[ fieldName ] = property.$jin_property_ensureType( args[ 0 ] )
return obj
} else {
if( obj.hasOwnProperty( fieldName ) ){
return obj[ fieldName ]
} else {
return obj[ fieldName ] = property.$jin_property_ensureType()
}
}
}
if( typeof type === 'string' ) type = $jin.lazy.glob( type )
property.$jin_property_ensureType = type || function( value ){ return nvalue }
property.$jin_method_resolveList = resolveList
return $jin.method( property )
}
$jin.klass = function $jin_klass( ){ // arguments: sourceName*, targetName
$jin.mixin.apply( this, arguments )
var name = arguments[ arguments.length - 1 ]
return $jin.mixin( '$jin_klass', name )
}
$jin.method( function $jin_klass_apply( klass, args ){
var obj = new klass
obj.constructor.apply( obj, args )
return obj
} )
$jin.method( function $jin_klass_toString( ){
return this.name
} )
$jin.method( function $jin_klass__constructor( config ){
if( !config ) return this
for( var key in config ){
this[ key ]( config[ key ] )
}
return this
} )
|
Цитата:
|
$имяПакета_имяМодуля_уника ьноеИмяВРамкахМодуля
|
Парсер лох, чо)
|
Хотя, тут можно и точку наверно использовать в качестве разделителя. Более существенные замечания будут?)
|
О, вспомнил! Надо твою статью про
yield перечитать до полного понимания. :) |
Она-то тут при чём? о_0" Да и не сильно она актуальна уже.. либу я ту переписал по другому.
|
Не при чем) Читал, когда в армии был. Что-то не найду ссылку. Там где пошагово расписывает про волокна. Еще осталась эта статья?
|
|
| Часовой пояс GMT +3, время: 11:46. |