Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 28.07.2013, 02:41
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

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


Как видно доступ к перегруженным методам возможен через их полные имена.

Указание перегружаемых методов для каждого перегружающего метода может показаться избыточным, однако перегрузка на уровне классов не может выявить конфликты при появлении новых методов в них. Поэтому такая перегрузка и не предусмотрена.

Багрепорты и идеи приветствуются)
__________________
.ня

Последний раз редактировалось tenshi, 02.08.2013 в 23:45.
Ответить с цитированием
  #2 (permalink)  
Старый 28.07.2013, 03:21
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

Забыл саму либу)

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
} )
__________________
.ня

Последний раз редактировалось tenshi, 02.08.2013 в 23:35.
Ответить с цитированием
  #3 (permalink)  
Старый 28.07.2013, 12:45
Аватар для nerv_
junior
Отправить личное сообщение для nerv_ Посмотреть профиль Найти все сообщения от nerv_
 
Регистрация: 29.11.2011
Сообщений: 3,924

Сообщение от tenshi
$jin_method
вЯваСкриптеCamelCase
__________________
Чебурашка стал символом олимпийских игр. А чего достиг ты?
Тишина - самый громкий звук
Ответить с цитированием
  #4 (permalink)  
Старый 28.07.2013, 14:33
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

$имяПакета_имяМодуля_уника ьноеИмяВРамкахМодуля
__________________
.ня
Ответить с цитированием
  #5 (permalink)  
Старый 28.07.2013, 14:34
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

Парсер лох, чо)
__________________
.ня
Ответить с цитированием
  #6 (permalink)  
Старый 28.07.2013, 14:49
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

Хотя, тут можно и точку наверно использовать в качестве разделителя. Более существенные замечания будут?)
__________________
.ня
Ответить с цитированием
  #7 (permalink)  
Старый 28.07.2013, 22:31
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

О, вспомнил! Надо твою статью про yield перечитать до полного понимания.

Последний раз редактировалось Octane, 28.07.2013 в 23:36.
Ответить с цитированием
  #8 (permalink)  
Старый 28.07.2013, 23:04
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

Она-то тут при чём? о_0" Да и не сильно она актуальна уже.. либу я ту переписал по другому.
__________________
.ня
Ответить с цитированием
  #9 (permalink)  
Старый 28.07.2013, 23:36
Отправить личное сообщение для Octane Посмотреть профиль Найти все сообщения от Octane  
Регистрация: 10.07.2008
Сообщений: 3,873

Не при чем) Читал, когда в армии был. Что-то не найду ссылку. Там где пошагово расписывает про волокна. Еще осталась эта статья?
Ответить с цитированием
  #10 (permalink)  
Старый 29.07.2013, 09:48
Профессор
Отправить личное сообщение для tenshi Посмотреть профиль Найти все сообщения от tenshi
 
Регистрация: 20.03.2008
Сообщений: 1,183

http://hyoo.ru/?article=%D0%92%D0%BE...author=Nin+Jin
__________________
.ня
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Снова вернуть обработчик, on(), off() Deliaz jQuery 4 11.08.2012 19:23
И снова драг энд дроп :) (Sandr) Элементы интерфейса 9 08.03.2012 23:23
Снова о slideToggle. Артефакты в ие9. Nyamo jQuery 1 27.01.2012 11:17
Снова динамический select Lion_astana Элементы интерфейса 4 19.11.2010 11:48
Снова проблема с событиями boneg Events/DOM/Window 0 13.10.2010 18:05