Package couchdbkit :: Package designer :: Module macros
[hide private]
[frames] | no frames]

Source Code for Module couchdbkit.designer.macros

  1  # -*- coding: utf-8 -*- 
  2  # 
  3  # This file is part of couchdbkit released under the MIT license.  
  4  # See the NOTICE for more information. 
  5   
  6  """ 
  7  Macros used by loaders. compatible with couchapp. It allow you to include code, 
  8  design docs members inside your views, shows and lists. 
  9   
 10  for example to include a code, add just after first function the line : 
 11       
 12      // !code relativepath/to/some/code.js 
 13       
 14  To include a member of design doc and use it as a simple javascript object : 
 15   
 16      // !json some.member.i.want.to.include 
 17       
 18  All in one, example of a view : 
 19   
 20      function(doc) { 
 21          !code _attachments/js/md5.js 
 22           
 23          if (doc.type == "user") { 
 24              doc.gravatar = hex_md5(user.email); 
 25              emit(doc.username, doc) 
 26          } 
 27      } 
 28   
 29  This example includes md5.js code and uses md5 function to create gravatar hash 
 30  in your views.  So you could just store raw data in your docs and calculate 
 31  hash when views are updated. 
 32   
 33  """ 
 34  import glob 
 35  from hashlib import md5 
 36  import logging 
 37  import os 
 38  import re 
 39   
 40  from ..exceptions import MacroError 
 41  from ..utils import read_file, read_json, to_bytestring, json 
 42   
 43  logger = logging.getLogger(__name__) 
 44   
 45   
46 -def package_shows(doc, funcs, app_dir, objs):
47 apply_lib(doc, funcs, app_dir, objs)
48
49 -def package_views(doc, views, app_dir, objs):
50 for view, funcs in views.iteritems(): 51 if hasattr(funcs, "items"): 52 apply_lib(doc, funcs, app_dir, objs)
53
54 -def apply_lib(doc, funcs, app_dir, objs):
55 for k, v in funcs.items(): 56 if not isinstance(v, basestring): 57 continue 58 else: 59 logger.debug("process function: %s" % k) 60 old_v = v 61 try: 62 funcs[k] = run_json_macros(doc, 63 run_code_macros(v, app_dir), app_dir) 64 except ValueError, e: 65 raise MacroError( 66 "Error running !code or !json on function \"%s\": %s" % (k, e)) 67 if old_v != funcs[k]: 68 objs[md5(to_bytestring(funcs[k])).hexdigest()] = old_v
69
70 -def run_code_macros(f_string, app_dir):
71 def rreq(mo): 72 # just read the file and return it 73 path = os.path.join(app_dir, mo.group(2).strip()) 74 library = '' 75 filenum = 0 76 for filename in glob.iglob(path): 77 logger.debug("process code macro: %s" % filename) 78 try: 79 cnt = read_file(filename) 80 if cnt.find("!code") >= 0: 81 cnt = run_code_macros(cnt, app_dir) 82 library += cnt 83 except IOError, e: 84 raise MacroError(str(e)) 85 filenum += 1 86 87 if not filenum: 88 raise MacroError( 89 "Processing code: No file matching '%s'" % mo.group(2)) 90 return library
91 92 re_code = re.compile('(\/\/|#)\ ?!code (.*)') 93 return re_code.sub(rreq, f_string) 94
95 -def run_json_macros(doc, f_string, app_dir):
96 included = {} 97 varstrings = [] 98 99 def rjson(mo): 100 if mo.group(2).startswith('_attachments'): 101 # someone want to include from attachments 102 path = os.path.join(app_dir, mo.group(2).strip()) 103 filenum = 0 104 for filename in glob.iglob(path): 105 logger.debug("process json macro: %s" % filename) 106 library = '' 107 try: 108 if filename.endswith('.json'): 109 library = read_json(filename) 110 else: 111 library = read_file(filename) 112 except IOError, e: 113 raise MacroError(str(e)) 114 filenum += 1 115 current_file = filename.split(app_dir)[1] 116 fields = current_file.split('/') 117 count = len(fields) 118 include_to = included 119 for i, field in enumerate(fields): 120 if i+1 < count: 121 include_to[field] = {} 122 include_to = include_to[field] 123 else: 124 include_to[field] = library 125 if not filenum: 126 raise MacroError( 127 "Processing code: No file matching '%s'" % mo.group(2)) 128 else: 129 logger.debug("process json macro: %s" % mo.group(2)) 130 fields = mo.group(2).strip().split('.') 131 library = doc 132 count = len(fields) 133 include_to = included 134 for i, field in enumerate(fields): 135 if not field in library: 136 logger.warning( 137 "process json macro: unknown json source: %s" % mo.group(2)) 138 break 139 library = library[field] 140 if i+1 < count: 141 include_to[field] = include_to.get(field, {}) 142 include_to = include_to[field] 143 else: 144 include_to[field] = library 145 146 return f_string
147 148 def rjson2(mo): 149 return '\n'.join(varstrings) 150 151 re_json = re.compile('(\/\/|#)\ ?!json (.*)') 152 re_json.sub(rjson, f_string) 153 154 if not included: 155 return f_string 156 157 for k, v in included.iteritems(): 158 varstrings.append("var %s = %s;" % (k, json.dumps(v).encode('utf-8'))) 159 160 return re_json.sub(rjson2, f_string) 161