Permalink
Browse files

* add registerProcessor() method

  • Loading branch information...
1 parent b433bc5 commit d502d879bfbf8c6fbd3182ede645aa9aa293fa3d @Meettya committed Mar 16, 2013
View
@@ -1,7 +1,13 @@
+## 0.2.5 / 2013/03-16 10:00 PM
+
+ - Add registerProcessor() method for custom file processors
+ - Huge refactor
+ - Update docs
+
## 0.2.3 / 2013/03-15 01:00 AM
- Add settings to Clinch constructor - 'jade', 'strict', 'inject'
- - Huge refactor to DiC
+ - Huge refactor to Dependency Injector Container
- Update docs
## 0.2.1 / 2013/03-05 02:00 PM
View
@@ -11,6 +11,14 @@ YA ComonJS to browser packer tool, well-suited for tiny widgets by small overhea
- `.eco` - precompile to JavaScript function
- `.jade` - precompile it in [client-mode](https://github.com/visionmedia/jade#a4) way
+## what about my custom template engine?
+
+This possibility almost exists - **clinch** from 0.2.5 have API for third party processors, but template engine must support template-to-function precompilation.
+
+For example, **Jade** have it, but for **Handlebars** I can't find it. If you know some way to use it - please, advise me.
+
+More info and example - below at description of method `registerProcessor()`
+
### More about .jade
Compiled [client-mode](https://github.com/visionmedia/jade#a4) template may be used wia `require()`. More information at './test', also examples was placed in wiki [jade template engine](https://github.com/Meettya/clinch/wiki/Jade-template-engine-support). In browser should be pre-loaded Jade's `runtime.js`.
@@ -90,6 +98,29 @@ And in browser function may be accessed in this way
`cb` - standard callback, all in **clinch** are async
+### registerProcessor()
+
+ packer.registerProcessor file_extention, fn
+
+This method allow to register any file content processor, which will be used to process files with `file_extention`.
+
+`file_extention` - file extension to proceed
+`fn` - processor function
+
+Example:
+
+ # add .econ processor
+ packer.registerProcessor '.econ', (file_content, filename, cb) ->
+ content = Eco.precompile file_content
+ cb null, "module.exports = #{content}"
+
+At now **clinch** will be compile all required `.econ` files with this function.
+
+And in module code:
+
+ template = require './template' # ./template.econ, extension may be omitted
+ res = template data # res now is some html-contented string
+
### flushCache()
packer.flushCache()
View
@@ -14,6 +14,14 @@
- `.eco` - прекомпилируется как JavaScript функция
- `.jade` - прекомпилируется как [client-mode](https://github.com/visionmedia/jade#a4) вариант
+## а можно подключить мой любимый шаблонизатор?
+
+Такая возможность почти есть - **clinch** с версии 0.2.5 реализует возможность подключения сторонних парсеров, но со стороны парсера должна быть поддержка предкомпиляции щаблона в функцию.
+
**Jade** такая возможность есть, у Handlebars я ее не нашел. Если это все же возможно - сообщите мне.
+
+Подробност и и пример - ниже, в описании метода `registerProcessor()`
+
### Немного про .jade
Скомпилированный [client-mode](https://github.com/visionmedia/jade#a4) шаблон может быть запрошен через `require()`. Подробнее можно посмотреть в тестах, так же пример есть на страничке wiki [jade template engine](https://github.com/Meettya/clinch/wiki/Jade-template-engine-support). В браузере необходимо загрузить `runtime.js` от **Jade**.
@@ -124,6 +132,30 @@
`cb` - стандартный коллбек, для работы с результатами, все в **clinch** асинхронно.
+### registerProcessor()
+
+ packer.registerProcessor file_extention, fn
+
+Данный метод позволяет зарегистрировать произвольный обработчик контента файла, который будет использован для обработки файла с указанным разрешением.
+
+`file_extention` - разрешение файла, которое будет обработано
+`fn` - функция для обработки файла
+
+Простой пример:
+
+ # add .econ processor
+ packer.registerProcessor '.econ', (file_content, filename, cb) ->
+ content = Eco.precompile file_content
+ cb null, "module.exports = #{content}"
+
+Теперь **clinch** будет компилировать указаным образом все запрошенные файлы с разрешением `.econ`
+
+Т.е. в коде модуля можно будет написать так
+
+ template = require './template' # ./template.econ, расширение можно не указывать
+ res = template data # в res будет какой-то html
+
+
### flushCache()
packer.flushCache()
@@ -0,0 +1,6 @@
+
+
+packer.registerProcessor '.handelbar', (data, filename, cb) ->
+ content = Handlebar.compile data
+ res = "module.exports = #{content}"
+ cb null, res
View
@@ -1,6 +1,6 @@
{
"name": "clinch",
- "version": "0.2.3",
+ "version": "0.2.5",
"description": "YA ComonJS to browser packer tool, well-suited for widgets by small overhead and big app by smart settings",
"main": "./src/app.coffee",
"scripts": {
@@ -17,7 +17,7 @@
"bundle",
"npm",
"javascript"
- ],
+ ],
"author": "Dmitrii Karpich <meettya@gmail.com>",
"license": "MIT",
"dependencies": {
View
@@ -2,6 +2,8 @@
This is main entry point for Clinch - API and setting here
###
+_ = require 'lodash'
+
# its our registry
DIContainer = require "./di_container"
@@ -27,6 +29,22 @@ class Clinch
gatherer = @_dic_obj_.getComponent 'Gatherer'
gatherer.resetCaches()
+
+ ###
+ This method add third party file processor to Clinch
+ ###
+ registerProcessor : (file_extention, processor_fn) ->
+ # some naive checks
+ unless _.isString file_extention
+ throw TypeError "file extention must be a String but get |#{file_extention}|"
+ unless _.isFunction processor_fn
+ throw TypeError "processor must be a Function but get |#{processor_fn}|"
+
+ processor_obj = {}
+ processor_obj[file_extention] = processor_fn
+
+ @_dic_obj_.addComponentsSettings 'FileProcessor' , 'third_party_compilers', processor_obj
+
###
This internal method used to configure components in DiC
###
View
@@ -9,6 +9,9 @@ Gatherer = require './gatherer'
FileProcessor = require './file_processor'
BundleProcessor = require './bundle_processor'
+# for debug
+# util = require 'util'
+
class DIContainer
constructor : ->
@_packer_ = null
@@ -20,43 +23,58 @@ class DIContainer
###
This method simple setter for components settings
+ its wipe out old values
chainable
###
setComponentsSettings : (options = {}) ->
for own key, value of options
- # just flat syntax
- up_key = key.toUpperCase()
-
- unless @_component_settings_[up_key]
- throw Error "don't know component name |#{key}|, mistype?"
+ up_key = @_upperCaseWithExistenceCheck key
@_component_settings_[up_key] = value
# clear cache to re-build new objects with new settings
@_flushComponentsChache()
this
###
- This internal method to flush all objects cache
- used if settings changed
- YES, its copy-paste, but we are MUST to declare all object properties in constructor
+ This method add some deep settings to components settings
+ only overwrite old deep settings, but not all key
+ chainable
###
- _flushComponentsChache : ->
- @_packer_ = null
- @_gatherer_ = null
- @_file_processor_ = null
- @_bundle_processor_ = null
+ addComponentsSettings : (component_name, path..., new_value_obj) ->
+
+ up_key = @_upperCaseWithExistenceCheck component_name
+ # we are use _.reduce by side-effect, in that step new value will be injected
+ last_path_idx = path.length - 1
+
+ deep_walker = (accumulator, step_val, idx) ->
+ # ensure deep bulder may use object
+ unless accumulator[step_val]
+ accumulator[step_val] = {}
+
+ # just inject new value
+ if idx is last_path_idx
+ for [key, value] in _.pairs new_value_obj
+ accumulator[step_val][key] = value
+ null
+ # or go deeper
+ else
+ accumulator = accumulator[step_val]
- null
+ _.reduce path, deep_walker, @_component_settings_[up_key]
+ # clear cache to re-build new objects with new settings
+ @_flushComponentsChache()
+ this
+
###
This method return component by it name
may recursive resolve dependencies
###
getComponent : (component_name) ->
- up_name = component_name.toUpperCase()
+ up_name = @_upperCaseWithExistenceCheck component_name
settings = @_component_settings_[up_name]
switch up_name
@@ -73,6 +91,32 @@ class DIContainer
throw Error "418! don't know component |#{component_name}|"
###
+ This internal method to flush all objects cache
+ used if settings changed
+ YES, its copy-paste, but we are MUST to declare all object properties in constructor
+ ###
+ _flushComponentsChache : ->
+ @_packer_ = null
+ @_gatherer_ = null
+ @_file_processor_ = null
+ @_bundle_processor_ = null
+
+ null
+
+ ###
+ This internal method to check is uppercased name exists in @_component_settings_
+ return uppercased name or throw error
+ ###
+ _upperCaseWithExistenceCheck : (key) ->
+ # just flat syntax
+ up_key = key.toUpperCase()
+
+ unless @_component_settings_[up_key]
+ throw Error "don't know component name |#{key}|, mistype?"
+
+ up_key
+
+ ###
Internal initor to reduce constructor
###
_initComponentSetting : ->
View
@@ -32,18 +32,24 @@ class FileProcessor
CS_BARE = yes # use bare to compile without a top-level function wrapper
constructor: (@_options_={}) ->
- @_compillers_ = @_getAsyncCompilers()
+ @_compilers_ = @_getAsyncCompilers @_getJadeSettings @_options_.jade
+ # and add third party compilers
+ _.assign @_compilers_, @_options_.third_party_compilers
###
This method load one file and, if it needed, compile it
###
loadFile : (rejectOnInvalidFilenameType (filename, cb) ->
file_ext = path.extname filename
- if @_compillers_[file_ext]?
- @_compillers_[file_ext] filename, (err, data, must_be_parsed) ->
+ if @_compilers_[file_ext]?
+ fs.readFile filename, 'utf8', (err, data) =>
return cb err if err
- cb null, data, must_be_parsed
+ @_compilers_[file_ext] @_stripBOM(data), filename, (err, result, must_be_parsed) ->
+ return cb err if err
+ # TODO! add show_filename to settings and it works here
+ res = "\n// #{filename} \n" + result
+ cb null, res, must_be_parsed
else
cb null, false
@@ -67,7 +73,7 @@ class FileProcessor
This method return supported extentions
###
getSupportedFileExtentions : ->
- _.keys @_compillers_
+ _.keys @_compilers_
###
This method from node.js lib/module
@@ -79,59 +85,35 @@ class FileProcessor
if content.charCodeAt(0) is 0xFEFF then content.slice(1) else content
###
+ This internal method for Jade settings
+ ###
+ _getJadeSettings : (options = {})->
+ # looks strange, but all ok - main options, user, add-on
+ _.defaults {client: on}, options, pretty: on, self: on, compileDebug: off
+
+ ###
This is Async compilers list.
- @return - error, data, isRealCode (ie. may have 'require' and need to be processed)
+ @return - error, data, isRealCode (ie. may have 'require' and should to be processed)
###
- _getAsyncCompilers : ->
- # dont want to bind all callbacks
- stripBOM = @_stripBOM
- jade_settings = @_options_.jade or {}
+ _getAsyncCompilers : (jade_settings) ->
- '.js' : (filename, cb) ->
- fs.readFile filename, 'utf8', (err, data) ->
- return cb err if err
- res = "\n// #{filename} \n" + stripBOM(data)
- cb null, res, yes
+ '.js' : (data, filename, cb) ->
+ cb null, data, yes
- '.json' : (filename, cb) ->
- fs.readFile filename, 'utf8', (err, data) ->
- return cb err if err
- res = "\n// #{filename} \n" + "module.exports = #{stripBOM(data)}"
- cb null, res
+ '.json' : (data, filename, cb) ->
+ cb null, "module.exports = #{data}"
- '.coffee' : (filename, cb) ->
- fs.readFile filename, 'utf8', (err, data) ->
- return cb err if err
- res = "\n// #{filename} \n" + CoffeeScript.compile(stripBOM(data), bare: CS_BARE)
- cb null, res, yes
+ '.coffee' : (data, filename, cb) ->
+ content = CoffeeScript.compile data, bare: CS_BARE
+ cb null, content, yes
- '.eco' : (filename, cb) ->
- fs.readFile filename, 'utf8', (err, data) ->
- return cb err if err
- content = Eco.precompile stripBOM(data)
- res = "\n// #{filename} \n" + "module.exports = #{content}"
- cb null, res
-
- '.jade' : (filename, cb) ->
- fs.readFile filename, 'utf8', (err, data) ->
- return cb err if err
-
- options =
- client: on
- filename : filename
-
- add_on_options =
- pretty : on
- self : on
- compileDebug : off
-
- # looks strange, but all ok - main options, user, add-on
- _.defaults options, jade_settings, add_on_options
-
- content = Jade.compile stripBOM(data), options
- res = "\n// #{filename} \n" + "module.exports = #{content}"
- cb null, res
+ '.eco' : (data, filename, cb) ->
+ content = Eco.precompile data
+ cb null, "module.exports = #{content}"
+ '.jade' : (data, filename, cb) ->
+ content = Jade.compile data, _.assign jade_settings, {filename}
+ cb null, "module.exports = #{content}"
module.exports = FileProcessor
Oops, something went wrong.

0 comments on commit d502d87

Please sign in to comment.