# -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function) __metaclass__ = type import re # Constants # ============================================================================ # Regular expression to split strings into their module namespace pieces by # `::` (Ruby) or `.` (Python, Javascript). # NAMESPACE_SPLIT_RE = re.compile(r'(?:\:\:)|\.|\#') # Functions # ============================================================================ def words(string): '''break a string into words >>> words('git_submodule_update') ['git', 'submodule', 'update'] >>> words("qb.DoSomething") ['qb', 'Do', 'Something'] >>> words("TestGem::SomeClass") ['Test', 'Gem', 'Some', 'Class'] >>> words("MyAPIClass") ['My', 'API', 'Class'] >>> words('ThisIsAName') ['This', 'Is', 'A', 'Name'] >>> words('404Error') ['404', 'Error'] >>> words('MyPackageV1') ['My', 'Package', 'V', '1'] # Don't work with doctest I guess..? # >>> [print(_) for _ in words(u'中文')] # [u'中文'] ''' consumers = [ [tag, [re.compile(pattern, re.U) for pattern in patterns]] for tag, patterns in [ ['break', [r'([\W\_]+)']], ['lower_case', [r'([a-z]+)']], ['capitalized', [r'([A-Z][a-z]+)']], ['acronym', [ r'([A-Z]+)[A-Z][a-z]', r'([A-Z]+)[0-9]', r'([A-Z]+)\z', ]], ['number', [r'([0-9]+)']], ['other', [r'([^0-9a-zA-Z]+)']], ] ] def find(remaining): for tag, exps in consumers: for exp in exps: # print("matching %s %s %s" % (tag, exp, remaining)) match = exp.match(remaining) if match: # print("matched %s! %s" % (tag, match.group(0))) return [tag, exp, match] raise StandardError("bad string: %s" % remaining) index = 0 results = [] remaining = string while len(remaining) > 0: [tag, exp, match] = find(remaining) if tag != 'break': results.append(remaining[:match.end(1)]) remaining = remaining[match.end(1):] return results def snake(name): ''' Turn a name into underscore-separated lower case. >>> snake('git_submodule_update') 'git_submodule_update' >>> snake("qb.DoSomething") 'qb_do_something' >>> snake("TestGem::SomeClass") 'test_gem_some_class' >>> snake("MyAPIClass") 'my_api_class' >>> snake('ThisIsAName') 'this_is_a_name' >>> snake('404Error') '404_error' >>> snake('MyPackageV1') 'my_package_v_1' ''' return '_'.join([part.lower() for part in words(name)]) def filepath(name): ''' Turn a name into a file path. >>> filepath('TestGem::SomeClass') 'test_gem/some_class' >>> filepath('TestGem::SomeClass#that_method') 'test_gem/some_class/that_method' # TODO # >>> filepath("TestGem::SomeClass How to do something") # 'test_gem/some_class/how_to_do_something' >>> filepath('qb.strings.filepath') 'qb/strings/filepath' ''' namespaces = NAMESPACE_SPLIT_RE.split(name) snaked = [snake(words_) for words_ in namespaces] joined = "/".join(snaked) return joined # testing - call camel_case on first cli arg and print result if __name__ == '__main__': import doctest doctest.testmod()