Skip to content

Commit

Permalink
Merge pull request #42 from HubSpot/context
Browse files Browse the repository at this point in the history
Fixing context bugs via direct assignment. Fixes #41.
  • Loading branch information
aaylward committed Jul 1, 2013
2 parents 243199e + 701a769 commit 2a06256
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 90 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,14 @@ Note that the `phantomjs` executable needs to be in the system `PATH` for grunt

## Release Notes

### 1.4.2

- fix [#41](https://github.com/HubSpot/humanize/issues/41)

### 1.4.1

- documentation update for npm

### 1.4.0

- add optional `downCaseTail` argument to [Humanize.capitalize](https://github.com/HubSpot/humanize#capitalize)
Expand All @@ -358,11 +366,11 @@ Note that the `phantomjs` executable needs to be in the system `PATH` for grunt
- [Release Notes](https://github.com/HubSpot/humanize/tree/master#release-notes) added to README

### 1.3.4
- fix [#33](https://github.com/HubSpot/humanize/issues/33) (affected users for version <= 1.3.3)
- fix [#33](https://github.com/HubSpot/humanize/issues/33)

### 1.3.3

- fix [#27](https://github.com/HubSpot/humanize/issues/27) (affected node users for version <= 1.3.2)
- fix [#27](https://github.com/HubSpot/humanize/issues/27)

## License
Copyright (c) 2013 HubSpotDev
Expand Down
79 changes: 40 additions & 39 deletions coffee/src/humanize.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ timeFormats = [
}
]

@Humanize = {}
Humanize = {}

# Converts a large integer to a friendly text representation.
@Humanize.intword = (number, charWidth, decimals=2) ->
Humanize.intword = (number, charWidth, decimals=2) ->
###
# This method is deprecated. Please use compactInteger instead.
# intword will be going away in the next major version.
###
@compactInteger(number, decimals)
Humanize.compactInteger(number, decimals)

# converts an integer into its most compact representation
@Humanize.compactInteger = (input, decimals=0) ->
Humanize.compactInteger = (input, decimals=0) ->
decimals = Math.max decimals, 0
number = parseInt input, 10
signString = if number < 0 then "-" else ""
Expand Down Expand Up @@ -87,24 +87,24 @@ timeFormats = [
output

# Converts an integer to a string containing commas every three digits.
@Humanize.intcomma = @Humanize.intComma = (number, decimals=0) -> @formatNumber number, decimals
Humanize.intcomma = Humanize.intComma = (number, decimals=0) -> Humanize.formatNumber number, decimals

# Formats the value like a 'human-readable' file size (i.e. '13 KB', '4.1 MB', '102 bytes', etc).
@Humanize.filesize = @Humanize.fileSize = (filesize) ->
Humanize.filesize = Humanize.fileSize = (filesize) ->
if filesize >= 1073741824
sizeStr = @formatNumber(filesize / 1073741824, 2, "") + " GB"
sizeStr = Humanize.formatNumber(filesize / 1073741824, 2, "") + " GB"
else if filesize >= 1048576
sizeStr = @formatNumber(filesize / 1048576, 2, "") + " MB"
sizeStr = Humanize.formatNumber(filesize / 1048576, 2, "") + " MB"
else if filesize >= 1024
sizeStr = @formatNumber(filesize / 1024, 0) + " KB"
sizeStr = Humanize.formatNumber(filesize / 1024, 0) + " KB"
else
sizeStr = @formatNumber(filesize, 0) + @pluralize filesize, " byte"
sizeStr = Humanize.formatNumber(filesize, 0) + Humanize.pluralize filesize, " byte"

sizeStr

# Formats a number to a human-readable string.
# Localize by overriding the precision, thousand and decimal arguments.
@Humanize.formatNumber = (number, precision=0, thousand=",", decimal=".") ->
Humanize.formatNumber = (number, precision=0, thousand=",", decimal=".") ->

# Create some private utility functions to make the computational
# code that follows much easier to read.
Expand All @@ -116,13 +116,13 @@ timeFormats = [
number.substr(position).replace /(\d{3})(?=\d)/g, "$1" + thousand

decimals = (number, decimal, usePrecision) =>
if usePrecision then decimal + @toFixed(Math.abs(number), usePrecision).split(".")[1] else ""
if usePrecision then decimal + Humanize.toFixed(Math.abs(number), usePrecision).split(".")[1] else ""

usePrecision = @normalizePrecision precision
usePrecision = Humanize.normalizePrecision precision

# Do some calc
negative = number < 0 and "-" or ""
base = parseInt(@toFixed(Math.abs(number or 0), usePrecision), 10) + ""
base = parseInt(Humanize.toFixed(Math.abs(number or 0), usePrecision), 10) + ""
mod = if base.length > 3 then base.length % 3 else 0

# Format the number
Expand All @@ -132,20 +132,20 @@ timeFormats = [
decimals(number, decimal, usePrecision)

# Fixes binary rounding issues (eg. (0.615).toFixed(2) === "0.61")
@Humanize.toFixed = (value, precision) ->
precision ?= @normalizePrecision precision, 0
Humanize.toFixed = (value, precision) ->
precision ?= Humanize.normalizePrecision precision, 0
power = Math.pow 10, precision

# Multiply up by precision, round accurately, then divide and use native toFixed()
(Math.round(value * power) / power).toFixed precision

# Ensures precision value is a positive integer
@Humanize.normalizePrecision = (value, base) ->
Humanize.normalizePrecision = (value, base) ->
value = Math.round Math.abs value
if isNaN(value) then base else value

# Converts an integer to its ordinal as a string.
@Humanize.ordinal = (value) ->
Humanize.ordinal = (value) ->
number = parseInt value, 10

return value if number is 0
Expand All @@ -167,7 +167,7 @@ timeFormats = [
"#{ number }#{ end }"

# Interprets numbers as occurences. Also accepts an optional array/map of overrides.
@Humanize.times = (value, overrides={}) ->
Humanize.times = (value, overrides={}) ->
if isFinite(value) and value >= 0
number = parseFloat value
smallTimes = ['never', 'once', 'twice']
Expand All @@ -177,22 +177,22 @@ timeFormats = [
"#{smallTimes[number]?.toString() or number.toString() + ' times'}"

# Returns the plural version of a given word if the value is not 1. The default suffix is 's'.
@Humanize.pluralize = (number, singular, plural) ->
Humanize.pluralize = (number, singular, plural) ->
return unless number? and singular?

plural ?= singular + "s"

if parseInt(number, 10) is 1 then singular else plural

# Truncates a string if it is longer than the specified number of characters (inclusive). Truncated strings will end with a translatable ellipsis sequence ("…").
@Humanize.truncate = (str, length=100, ending='...') ->
Humanize.truncate = (str, length=100, ending='...') ->
if str.length > length
str.substring(0, length - ending.length) + ending
else
str

# Truncates a string after a certain number of words.
@Humanize.truncatewords = @Humanize.truncateWords = (string, length) ->
Humanize.truncatewords = Humanize.truncateWords = (string, length) ->
array = string.split " "
result = ""
i = 0
Expand All @@ -205,7 +205,7 @@ timeFormats = [
result += "..." if array.length > length

# Truncates a number to an upper bound.
@Humanize.truncatenumber = @Humanize.boundedNumber = (num, bound=100, ending="+") ->
Humanize.truncatenumber = Humanize.boundedNumber = (num, bound=100, ending="+") ->
result = null

if isFinite(num) and isFinite(bound)
Expand All @@ -214,7 +214,7 @@ timeFormats = [
(result or num).toString()

# Converts a list of items to a human readable string with an optional limit.
@Humanize.oxford = (items, limit, limitStr) ->
Humanize.oxford = (items, limit, limitStr) ->
numItems = items.length

if numItems < 2
Expand All @@ -226,7 +226,7 @@ timeFormats = [
else if limit? and numItems > limit
extra = numItems - limit
limitIndex = limit
limitStr ?= ", and #{extra} #{@pluralize(extra, 'other')}"
limitStr ?= ", and #{extra} #{Humanize.pluralize(extra, 'other')}"

else
limitIndex = -1
Expand All @@ -235,7 +235,7 @@ timeFormats = [
items.slice(0, limitIndex).join(', ') + limitStr

# Converts an object to a definition-like string
@Humanize.dictionary = (object, joiner=' is ', separator=', ') ->
Humanize.dictionary = (object, joiner=' is ', separator=', ') ->
result = ''

if object? and typeof object is 'object' and Object.prototype.toString.call(object) isnt '[object Array]'
Expand All @@ -248,11 +248,11 @@ timeFormats = [
result

# Describes how many times an item appears in a list
@Humanize.frequency = (list, verb) ->
Humanize.frequency = (list, verb) ->
return unless isArray(list)

len = list.length
times = @times len
times = Humanize.times len

if len is 0
str = "#{times} #{verb}"
Expand All @@ -261,10 +261,10 @@ timeFormats = [

str

@Humanize.pace = (value, intervalMs, unit='time') ->
Humanize.pace = (value, intervalMs, unit='time') ->
if value is 0 or intervalMs is 0
# Needs a better string than this...
return "No #{@pluralize(unit)}"
return "No #{Humanize.pluralize(unit)}"

# Expose these as overridables?
prefix = 'Approximately'
Expand All @@ -284,28 +284,28 @@ timeFormats = [
timeUnit = timeFormats[timeFormats.length - 1].name

roundedPace = Math.round relativePace
unit = @pluralize roundedPace, unit
unit = Humanize.pluralize roundedPace, unit

"#{prefix} #{roundedPace} #{unit} per #{timeUnit}"

# Converts newlines to <br/> tags
@Humanize.nl2br = (string, replacement='<br/>') ->
Humanize.nl2br = (string, replacement='<br/>') ->
string.replace /\n/g, replacement

# Converts <br/> tags to newlines
@Humanize.br2nl = (string, replacement='\r\n') ->
Humanize.br2nl = (string, replacement='\r\n') ->
string.replace /\<br\s*\/?\>/g, replacement

# Capitalizes first letter in a string
@Humanize.capitalize = (string, downCaseTail=false) ->
Humanize.capitalize = (string, downCaseTail=false) ->
"#{ string.charAt(0).toUpperCase() }#{ if downCaseTail then string.slice(1).toLowerCase() else string.slice(1) }"

# Capitalizes the first letter of each word in a string
@Humanize.capitalizeAll = (string) ->
Humanize.capitalizeAll = (string) ->
string.replace /(?:^|\s)\S/g, (a) -> a.toUpperCase()

# Titlecase words in a string.
@Humanize.titlecase = @Humanize.titleCase = (string) ->
Humanize.titlecase = Humanize.titleCase = (string) ->
smallWords = /\b(a|an|and|at|but|by|de|en|for|if|in|of|on|or|the|to|via|vs?\.?)\b/i
internalCaps = /\S+[A-Z]+\S*/
splitOnWhiteSpaceRegex = /\s+/
Expand All @@ -320,17 +320,18 @@ timeFormats = [
continue

if firstOrLast and (index is 0 or index is stringArray.length - 1)
titleCasedArray.push if internalCaps.test(word) then word else @capitalize(word)
titleCasedArray.push if internalCaps.test(word) then word else Humanize.capitalize(word)
continue

if internalCaps.test(word)
titleCasedArray.push(word)
else if smallWords.test(word)
titleCasedArray.push(word.toLowerCase())
else
titleCasedArray.push(@capitalize(word))
titleCasedArray.push(Humanize.capitalize(word))

titleCasedArray.join(if hyphenated then '-' else ' ')
doTitleCase(string)

module?.exports = @Humanize
@Humanize = Humanize
module?.exports = Humanize
19 changes: 13 additions & 6 deletions coffee/test/test_humanize.spec.coffee
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
describe 'When using method via destructured assignment', ->
it 'should properly reference other Humanize methods', ->
spyOn(Humanize, 'capitalize').andCallThrough()

{titlecase} = Humanize
expect(titlecase('ship it')).toEqual('Ship It')
expect(Humanize.capitalize).toHaveBeenCalled()

describe 'Millions as word', ->
it 'should pass', ->
Expand Down Expand Up @@ -235,24 +242,24 @@ describe 'Capitalizing words appropriately', ->
it 'should convert "cool the iTunes cake, O\'Malley!" to "Cool the iTunes Cake, O\'Malley!"', ->
expect(Humanize.titlecase('cool the iTunes cake, O\'Malley!')).toEqual('Cool the iTunes Cake, O\'Malley!')
expect(Humanize.titleCase('cool the iTunes cake, O\'Malley!')).toEqual('Cool the iTunes Cake, O\'Malley!')

it 'should convert "cul-de-sac drive-by" to "Cul-de-Sac Drive-By"', ->
expect(Humanize.titlecase('cul-de-sac drive-by')).toEqual('Cul-de-Sac Drive-By')
expect(Humanize.titleCase('cul-de-sac drive-by')).toEqual('Cul-de-Sac Drive-By')

it 'should convert "ultra-book By iTunes" to "Ultra-Book by iTunes"', ->
expect(Humanize.titlecase('ultra-book By iTunes')).toEqual('Ultra-Book by iTunes')
expect(Humanize.titleCase('ultra-book By iTunes')).toEqual('Ultra-Book by iTunes')

it 'should convert "by-the-book ultra-book By iTunes" to "By-the-Book Ultra-Book by iTunes"', ->
expect(Humanize.titlecase('by-the-book ultra-book By iTunes')).toEqual('By-the-Book Ultra-Book by iTunes')
expect(Humanize.titleCase('by-the-book ultra-book By iTunes')).toEqual('By-the-Book Ultra-Book by iTunes')

it 'should convert "by-the-book ultra-book by-the-by iTunes" to "By-the-Book Ultra-Book by-the-by iTunes"', ->
expect(Humanize.titlecase('by-the-book ultra-book by-the-by iTunes')).toEqual('By-the-Book Ultra-Book by-the-by iTunes')
expect(Humanize.titleCase('by-the-book ultra-book by-the-by iTunes')).toEqual('By-the-Book Ultra-Book by-the-by iTunes')

it 'should convert "by-the-by is not iTunes-O\'Malley\'s favorite of the new-on-a-book" to "By-the-by Is Not iTunes-O\'Malley\'s Favorite of the New-on-a-Book"', ->
expect(Humanize.titlecase('by-the-by is not iTunes-O\'Malley\'s favorite of the new-on-a-book')).toEqual('By-the-By Is Not iTunes-O\'Malley\'s Favorite of the New-on-a-Book')
expect(Humanize.titleCase('by-the-by is not iTunes-O\'Malley\'s favorite of the new-on-a-book')).toEqual('By-the-By Is Not iTunes-O\'Malley\'s Favorite of the New-on-a-Book')

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "humanize-plus",
"title": "Humanize",
"description": "A simple utility library for making the web more humane.",
"version": "1.4.1",
"version": "1.4.2",
"homepage": "https://github.com/HubSpot/humanize",
"main": "./public/src/humanize.js",
"author": {
Expand Down
Loading

0 comments on commit 2a06256

Please sign in to comment.