├── .gitignore ├── lib ├── nytimes-style │ ├── version.rb │ └── states.yml └── nytimes-style.rb ├── Rakefile ├── README.rdoc ├── nytimes-style.gemspec ├── test └── test_nytimes_style.rb ├── docco.css └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | pkg/* 2 | *.gem 3 | .bundle 4 | -------------------------------------------------------------------------------- /lib/nytimes-style/version.rb: -------------------------------------------------------------------------------- 1 | module Nytimes 2 | module Style 3 | VERSION = "0.7.0" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | desc 'Run all tests' 2 | task :test do 3 | $LOAD_PATH.unshift(File.expand_path('test')) 4 | require 'redgreen' if Gem.available?('redgreen') 5 | require 'test/unit' 6 | require './test/test_nytimes_style' 7 | end 8 | 9 | desc 'Build annotated source code' 10 | task :docs do 11 | sh 'rocco lib/nytimes-style.rb && mv lib/nytimes-style.html ./index.html' 12 | end 13 | 14 | namespace :gem do 15 | 16 | desc 'Build and install the gem' 17 | task :install do 18 | sh "gem build nytimes-style.gemspec" 19 | sh "gem install #{Dir['*.gem'].join(' ')} --local --no-ri --no-rdoc" 20 | end 21 | 22 | desc 'Uninstall the jammit gem' 23 | task :uninstall do 24 | sh "gem uninstall -x nytimes-style" 25 | end 26 | 27 | end 28 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = nytimes-style 2 | 3 | Helper methods for generating text that conforms to The New York Times Manual of Style and Usage. 4 | 5 | Annotated source code: http://ascheink.github.com/nytimes-style 6 | 7 | == INSTALLATION 8 | 9 | gem install nytimes-style 10 | 11 | == USAGE 12 | 13 | require 'nytimes-style' 14 | include Nytimes::Style 15 | 16 | >> nytimes_date Date.today 17 | # => "May 12, 2011" 18 | 19 | >> nytimes_date Date.today, :hide_current_year => true, :day_of_week => true 20 | # => "Wednesday, June 15" 21 | 22 | >> nytimes_time Time.now, :hide_abbreviation => false 23 | # => "2:30 p.m." 24 | 25 | >> nytimes_state_abbrev 'AZ' 26 | # => "Ariz." 27 | 28 | >> nytimes_state_name '55' 29 | # => "Wisconsin" 30 | 31 | == CONTRIBUTORS 32 | 33 | Andrei Scheinkman, andreischeinkman@gmail.com 34 | 35 | Tyson Evans, tyson.evans@nytimes.com 36 | 37 | Derek Willis, dwillis@nytimes.com -------------------------------------------------------------------------------- /nytimes-style.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.push File.expand_path("../lib", __FILE__) 3 | require "nytimes-style/version" 4 | 5 | Gem::Specification.new do |s| 6 | s.name = "nytimes-style" 7 | s.version = Nytimes::Style::VERSION 8 | s.platform = Gem::Platform::RUBY 9 | s.authors = ["Andrei Scheinkman", "Tyson Evans", "Derek Willis"] 10 | s.email = ["andrei@nytimes.com", "tyson.evans@nytimes.com", "dwillis@nytimes.com"] 11 | s.homepage = "http://github.com/ascheink/nytimes-style" 12 | s.summary = %q{New York Times style} 13 | s.description = %q{Format numbers and dates according to The New York Times Manual of Style} 14 | 15 | s.files = `git ls-files`.split("\n") 16 | s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") 17 | s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } 18 | s.require_paths = ["lib"] 19 | end 20 | -------------------------------------------------------------------------------- /test/test_nytimes_style.rb: -------------------------------------------------------------------------------- 1 | require './lib/nytimes-style' 2 | 3 | 4 | class InheritedDateTime < DateTime; end 5 | class InheritedTime < Time; end 6 | 7 | class NytimesStyleTest < Test::Unit::TestCase 8 | include Nytimes::Style 9 | 10 | def test_dates 11 | date = Date.civil(2001, 9, 11) 12 | assert_equal "Sept. 11", nytimes_month_and_day(date) 13 | assert_equal "Sept. 11, 2001", nytimes_date(date) 14 | assert_raise(ArgumentError) { nytimes_month(0) } 15 | end 16 | 17 | def test_date_options 18 | date = Date.civil(2001, 9, 11) 19 | assert_equal "Tuesday, Sept. 11, 2001", nytimes_date(date, :day_of_week => true) 20 | assert_equal "Sept. 11, 2001", nytimes_date(date, :hide_current_year => true) 21 | this_year = Date.today.year 22 | recent_date = Date.civil(this_year, 2, 12) 23 | assert_equal "Feb. 12", nytimes_date(recent_date, :hide_current_year => true) 24 | end 25 | 26 | def test_time 27 | time = Time.local(2011, 7, 12, 14, 30, 30) 28 | assert_equal "2:30 p.m.", nytimes_time(time) 29 | assert_equal "2:30", nytimes_time(time, :hide_abbreviation => true) 30 | assert_raise(ArgumentError) { nytimes_time(Date.today) } 31 | assert_nothing_raised { nytimes_time(InheritedDateTime.new) } 32 | assert_nothing_raised { nytimes_time(InheritedTime.new) } 33 | end 34 | 35 | def test_state_abbrevs 36 | assert_equal 'Ariz.', nytimes_state_abbrev('AZ') 37 | assert_equal 'N.H.', nytimes_state_abbrev('New Hampshire') 38 | assert_equal 'Wis.', nytimes_state_abbrev(55) 39 | assert_raise(ArgumentError) { nytimes_state_abbrev('Canada') } 40 | end 41 | 42 | def test_state_names 43 | assert_equal 'Arizona', nytimes_state_name('AZ') 44 | assert_equal 'New Hampshire', nytimes_state_name('New Hampshire') 45 | assert_equal 'Wisconsin', nytimes_state_name(55) 46 | assert_raise(ArgumentError) { nytimes_state_name(242) } 47 | end 48 | 49 | def test_numbers 50 | assert_equal 'five', nytimes_number(5) 51 | assert_equal '12', nytimes_number(12) 52 | end 53 | 54 | end 55 | -------------------------------------------------------------------------------- /lib/nytimes-style.rb: -------------------------------------------------------------------------------- 1 | require 'date' 2 | require 'yaml' 3 | 4 | # A small set of helper methods for generating text that conforms to _The New York Times Manual of Style and Usage_, 5 | # hosted on [Github](https://github.com/ascheink/nytimes-style). 6 | module Nytimes 7 | module Style 8 | 9 | # > "In general, spell out the first nine cardinal and 10 | # > ordinal numbers [but] spell any number that begins a sentence..." 11 | # Exceptions include "ages of people 12 | # and animals," "sums of money," "degrees of temperature" and "mentions of the Twelve 13 | # Apostles and the Ten Commandments." 14 | def nytimes_number(n) 15 | if n < 10 16 | %w(one two three four five six seven eight nine)[n - 1] 17 | else 18 | n.to_s 19 | end 20 | end 21 | 22 | # > "Abbreviate the names of months from August through 23 | # > February in news copy when they are followed by numerals: Aug. 1; Sept. 24 | # > 2; Oct. 3; Nov. 4; Dec. 5; Jan. 6; Feb. 7. Do not abbreviate March, 25 | # > April, May, June and July except as a last resort in a chart or table." 26 | def nytimes_date(date, opts={}) 27 | str = "" 28 | str << date.strftime('%A, ') if opts[:day_of_week] 29 | str << nytimes_month_and_day(date) 30 | str << ", #{date.year}" unless opts[:hide_current_year] && date.year == Date.today.year 31 | return str 32 | end 33 | 34 | def nytimes_month_and_day(date) 35 | "#{nytimes_month date.month} #{date.day}" 36 | end 37 | 38 | def nytimes_month(month) 39 | raise ArgumentError.new "Unknown month: #{month}" unless (1..12).include? month 40 | %w(Jan. Feb. March April May June July Aug. Sept. Oct. Nov. Dec.)[month - 1] 41 | end 42 | 43 | # > "Use numerals in giving clock time: 10:30 a.m.; 10:30. 44 | # > Do not use half-past 10 except in a direct quotation. 45 | # > Also avoid the redundant 10:30 a.m. yesterday morning and Monday afternoon at 2 p.m." 46 | def nytimes_time(time, opts={}) 47 | raise ArgumentError.new "Time or DateTime required" unless time.is_a?(DateTime) || time.is_a?(Time) 48 | str = "" 49 | str << time.strftime("%l:%M").strip 50 | str << time.strftime(" %p").sub('PM','p.m.').sub('AM','a.m.') unless opts[:hide_abbreviation] 51 | str 52 | end 53 | 54 | # > "The abbreviation to be used for each state, after the names of cities, 55 | # > towns and counties… Use no 56 | # > spaces between initials like N.H. Do not abbreviate Alaska, Hawaii, Idaho, 57 | # > Iowa, Ohio and Utah. (Do not ordinarily use the Postal Service’s 58 | # > two-letter abbreviations; some are hard to tell apart on quick reading.)" 59 | def nytimes_state_abbrev(state_name_or_code) 60 | state = states[state_name_or_code] 61 | raise ArgumentError.new "Unknown postal code, state name or FIPS code: #{state_name_or_code}" unless state 62 | state['nytimes_abbrev'] 63 | end 64 | 65 | def nytimes_state_name(state_abbrev_or_code) 66 | state = states[state_abbrev_or_code] 67 | raise ArgumentError.new "Unknown postal code, abbreviation or FIPS code: #{state_abbrev_or_code}" unless state 68 | state['name'] 69 | end 70 | 71 | private 72 | 73 | STATE_DATA_FILE = File.join(File.dirname(__FILE__), 'nytimes-style/states.yml') 74 | 75 | def states 76 | @_nytimes_states ||= YAML::load(File.open(STATE_DATA_FILE)).inject({}) do |h, state| 77 | h.merge({ state['postal_code'] => state, state['name'] => state, state['fips_code'] => state }) 78 | end 79 | end 80 | 81 | 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /lib/nytimes-style/states.yml: -------------------------------------------------------------------------------- 1 | - fips_code: 1 2 | name: Alabama 3 | nytimes_abbrev: Ala. 4 | postal_code: AL 5 | - fips_code: 2 6 | name: Alaska 7 | nytimes_abbrev: Alaska 8 | postal_code: AK 9 | - fips_code: 4 10 | name: Arizona 11 | nytimes_abbrev: Ariz. 12 | postal_code: AZ 13 | - fips_code: 5 14 | name: Arkansas 15 | nytimes_abbrev: Ark. 16 | postal_code: AR 17 | - fips_code: 6 18 | name: California 19 | nytimes_abbrev: Calif. 20 | postal_code: CA 21 | - fips_code: 8 22 | name: Colorado 23 | nytimes_abbrev: Colo. 24 | postal_code: CO 25 | - fips_code: 9 26 | name: Connecticut 27 | nytimes_abbrev: Conn. 28 | postal_code: CT 29 | - fips_code: 10 30 | name: Delaware 31 | nytimes_abbrev: Del. 32 | postal_code: DE 33 | - fips_code: 11 34 | name: District of Columbia 35 | nytimes_abbrev: D.C. 36 | postal_code: DC 37 | - fips_code: 12 38 | name: Florida 39 | nytimes_abbrev: Fla. 40 | postal_code: FL 41 | - fips_code: 13 42 | name: Georgia 43 | nytimes_abbrev: Ga. 44 | postal_code: GA 45 | - fips_code: 15 46 | name: Hawaii 47 | nytimes_abbrev: Hawaii 48 | postal_code: HI 49 | - fips_code: 16 50 | name: Idaho 51 | nytimes_abbrev: Idaho 52 | postal_code: ID 53 | - fips_code: 17 54 | name: Illinois 55 | nytimes_abbrev: Ill. 56 | postal_code: IL 57 | - fips_code: 18 58 | name: Indiana 59 | nytimes_abbrev: Ind. 60 | postal_code: IN 61 | - fips_code: 19 62 | name: Iowa 63 | nytimes_abbrev: Iowa 64 | postal_code: IA 65 | - fips_code: 20 66 | name: Kansas 67 | nytimes_abbrev: Kan. 68 | postal_code: KS 69 | - fips_code: 21 70 | name: Kentucky 71 | nytimes_abbrev: Ky. 72 | postal_code: KY 73 | - fips_code: 22 74 | name: Louisiana 75 | nytimes_abbrev: La. 76 | postal_code: LA 77 | - fips_code: 23 78 | name: Maine 79 | nytimes_abbrev: Me. 80 | postal_code: ME 81 | - fips_code: 24 82 | name: Maryland 83 | nytimes_abbrev: Md. 84 | postal_code: MD 85 | - fips_code: 25 86 | name: Massachusetts 87 | nytimes_abbrev: Mass. 88 | postal_code: MA 89 | - fips_code: 26 90 | name: Michigan 91 | nytimes_abbrev: Mich. 92 | postal_code: MI 93 | - fips_code: 27 94 | name: Minnesota 95 | nytimes_abbrev: Minn. 96 | postal_code: MN 97 | - fips_code: 28 98 | name: Mississippi 99 | nytimes_abbrev: Miss. 100 | postal_code: MS 101 | - fips_code: 29 102 | name: Missouri 103 | nytimes_abbrev: Mo. 104 | postal_code: MO 105 | - fips_code: 30 106 | name: Montana 107 | nytimes_abbrev: Mont. 108 | postal_code: MT 109 | - fips_code: 31 110 | name: Nebraska 111 | nytimes_abbrev: Neb. 112 | postal_code: NE 113 | - fips_code: 32 114 | name: Nevada 115 | nytimes_abbrev: Nev. 116 | postal_code: NV 117 | - fips_code: 33 118 | name: New Hampshire 119 | nytimes_abbrev: N.H. 120 | postal_code: NH 121 | - fips_code: 34 122 | name: New Jersey 123 | nytimes_abbrev: N.J. 124 | postal_code: NJ 125 | - fips_code: 35 126 | name: New Mexico 127 | nytimes_abbrev: N.M. 128 | postal_code: NM 129 | - fips_code: 36 130 | name: New York 131 | nytimes_abbrev: N.Y. 132 | postal_code: NY 133 | - fips_code: 37 134 | name: North Carolina 135 | nytimes_abbrev: N.C. 136 | postal_code: NC 137 | - fips_code: 38 138 | name: North Dakota 139 | nytimes_abbrev: N.D. 140 | postal_code: ND 141 | - fips_code: 39 142 | name: Ohio 143 | nytimes_abbrev: Ohio 144 | postal_code: OH 145 | - fips_code: 40 146 | name: Oklahoma 147 | nytimes_abbrev: Okla. 148 | postal_code: OK 149 | - fips_code: 41 150 | name: Oregon 151 | nytimes_abbrev: Ore. 152 | postal_code: OR 153 | - fips_code: 42 154 | name: Pennsylvania 155 | nytimes_abbrev: Pa. 156 | postal_code: PA 157 | - fips_code: 44 158 | name: Rhode Island 159 | nytimes_abbrev: R.I. 160 | postal_code: RI 161 | - fips_code: 45 162 | name: South Carolina 163 | nytimes_abbrev: S.C. 164 | postal_code: SC 165 | - fips_code: 46 166 | name: South Dakota 167 | nytimes_abbrev: S.D. 168 | postal_code: SD 169 | - fips_code: 47 170 | name: Tennessee 171 | nytimes_abbrev: Tenn. 172 | postal_code: TN 173 | - fips_code: 48 174 | name: Texas 175 | nytimes_abbrev: Tex. 176 | postal_code: TX 177 | - fips_code: 49 178 | name: Utah 179 | nytimes_abbrev: Utah 180 | postal_code: UT 181 | - fips_code: 50 182 | name: Vermont 183 | nytimes_abbrev: Vt. 184 | postal_code: VT 185 | - fips_code: 51 186 | name: Virginia 187 | nytimes_abbrev: Va. 188 | postal_code: VA 189 | - fips_code: 53 190 | name: Washington 191 | nytimes_abbrev: Wash. 192 | postal_code: WA 193 | - fips_code: 54 194 | name: West Virginia 195 | nytimes_abbrev: W.Va. 196 | postal_code: WV 197 | - fips_code: 55 198 | name: Wisconsin 199 | nytimes_abbrev: Wis. 200 | postal_code: WI 201 | - fips_code: 56 202 | name: Wyoming 203 | nytimes_abbrev: Wyo. 204 | postal_code: WY 205 | - fips_code: 72 206 | name: Puerto Rico 207 | nytimes_abbrev: P.R. 208 | postal_code: PR 209 | -------------------------------------------------------------------------------- /docco.css: -------------------------------------------------------------------------------- 1 | /*--------------------- Layout and Typography ----------------------------*/ 2 | body { 3 | font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif; 4 | font-size: 16px; 5 | line-height: 24px; 6 | color: #252519; 7 | margin: 0; padding: 0; 8 | } 9 | a { 10 | color: #261a3b; 11 | } 12 | a:visited { 13 | color: #261a3b; 14 | } 15 | p { 16 | margin: 0 0 15px 0; 17 | } 18 | h1, h2, h3, h4, h5, h6 { 19 | margin: 40px 0 15px 0; 20 | } 21 | h3, h4, h5, h6 { 22 | margin-top: 20px; 23 | } 24 | #container { 25 | position: relative; 26 | } 27 | #background { 28 | position: fixed; 29 | top: 0; left: 580px; right: 0; bottom: 0; 30 | background: #f5f5ff; 31 | border-left: 1px solid #e5e5ee; 32 | z-index: -1; 33 | } 34 | #jump_to, #jump_page { 35 | background: white; 36 | -webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777; 37 | -webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px; 38 | font: 10px Arial; 39 | text-transform: uppercase; 40 | cursor: pointer; 41 | text-align: right; 42 | } 43 | #jump_to, #jump_wrapper { 44 | position: fixed; 45 | right: 0; top: 0; 46 | padding: 5px 10px; 47 | } 48 | #jump_wrapper { 49 | padding: 0; 50 | display: none; 51 | } 52 | #jump_to:hover #jump_wrapper { 53 | display: block; 54 | } 55 | #jump_page { 56 | padding: 5px 0 3px; 57 | margin: 0 0 25px 25px; 58 | } 59 | #jump_page .source { 60 | display: block; 61 | padding: 5px 10px; 62 | text-decoration: none; 63 | border-top: 1px solid #eee; 64 | } 65 | #jump_page .source:hover { 66 | background: #f5f5ff; 67 | } 68 | #jump_page .source:first-child { 69 | } 70 | table td { 71 | border: 0; 72 | outline: 0; 73 | } 74 | td.docs, th.docs { 75 | max-width: 500px; 76 | min-width: 500px; 77 | min-height: 5px; 78 | padding: 10px 25px 1px 50px; 79 | vertical-align: top; 80 | text-align: left; 81 | } 82 | .docs pre { 83 | margin: 15px 0 15px; 84 | padding-left: 15px; 85 | } 86 | .docs p tt, .docs p code { 87 | background: #f8f8ff; 88 | border: 1px solid #dedede; 89 | font-size: 12px; 90 | padding: 0 0.2em; 91 | } 92 | .octowrap { 93 | position: relative; 94 | } 95 | .octothorpe { 96 | font: 12px Arial; 97 | text-decoration: none; 98 | color: #454545; 99 | position: absolute; 100 | top: 3px; left: -20px; 101 | padding: 1px 2px; 102 | opacity: 0; 103 | -webkit-transition: opacity 0.2s linear; 104 | } 105 | td.docs:hover .octothorpe { 106 | opacity: 1; 107 | } 108 | td.code, th.code { 109 | padding: 14px 15px 16px 50px; 110 | width: 100%; 111 | vertical-align: top; 112 | background: #f5f5ff; 113 | border-left: 1px solid #e5e5ee; 114 | } 115 | pre, tt, code { 116 | font-size: 12px; line-height: 18px; 117 | font-family: Monaco, Consolas, "Lucida Console", monospace; 118 | margin: 0; padding: 0; 119 | } 120 | 121 | 122 | /*---------------------- Syntax Highlighting -----------------------------*/ 123 | td.linenos { background-color: #f0f0f0; padding-right: 10px; } 124 | span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } 125 | body .hll { background-color: #ffffcc } 126 | body .c { color: #408080; font-style: italic } /* Comment */ 127 | body .err { border: 1px solid #FF0000 } /* Error */ 128 | body .k { color: #954121 } /* Keyword */ 129 | body .o { color: #666666 } /* Operator */ 130 | body .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 131 | body .cp { color: #BC7A00 } /* Comment.Preproc */ 132 | body .c1 { color: #408080; font-style: italic } /* Comment.Single */ 133 | body .cs { color: #408080; font-style: italic } /* Comment.Special */ 134 | body .gd { color: #A00000 } /* Generic.Deleted */ 135 | body .ge { font-style: italic } /* Generic.Emph */ 136 | body .gr { color: #FF0000 } /* Generic.Error */ 137 | body .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 138 | body .gi { color: #00A000 } /* Generic.Inserted */ 139 | body .go { color: #808080 } /* Generic.Output */ 140 | body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 141 | body .gs { font-weight: bold } /* Generic.Strong */ 142 | body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 143 | body .gt { color: #0040D0 } /* Generic.Traceback */ 144 | body .kc { color: #954121 } /* Keyword.Constant */ 145 | body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */ 146 | body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */ 147 | body .kp { color: #954121 } /* Keyword.Pseudo */ 148 | body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */ 149 | body .kt { color: #B00040 } /* Keyword.Type */ 150 | body .m { color: #666666 } /* Literal.Number */ 151 | body .s { color: #219161 } /* Literal.String */ 152 | body .na { color: #7D9029 } /* Name.Attribute */ 153 | body .nb { color: #954121 } /* Name.Builtin */ 154 | body .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 155 | body .no { color: #880000 } /* Name.Constant */ 156 | body .nd { color: #AA22FF } /* Name.Decorator */ 157 | body .ni { color: #999999; font-weight: bold } /* Name.Entity */ 158 | body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 159 | body .nf { color: #0000FF } /* Name.Function */ 160 | body .nl { color: #A0A000 } /* Name.Label */ 161 | body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 162 | body .nt { color: #954121; font-weight: bold } /* Name.Tag */ 163 | body .nv { color: #19469D } /* Name.Variable */ 164 | body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 165 | body .w { color: #bbbbbb } /* Text.Whitespace */ 166 | body .mf { color: #666666 } /* Literal.Number.Float */ 167 | body .mh { color: #666666 } /* Literal.Number.Hex */ 168 | body .mi { color: #666666 } /* Literal.Number.Integer */ 169 | body .mo { color: #666666 } /* Literal.Number.Oct */ 170 | body .sb { color: #219161 } /* Literal.String.Backtick */ 171 | body .sc { color: #219161 } /* Literal.String.Char */ 172 | body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */ 173 | body .s2 { color: #219161 } /* Literal.String.Double */ 174 | body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 175 | body .sh { color: #219161 } /* Literal.String.Heredoc */ 176 | body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 177 | body .sx { color: #954121 } /* Literal.String.Other */ 178 | body .sr { color: #BB6688 } /* Literal.String.Regex */ 179 | body .s1 { color: #219161 } /* Literal.String.Single */ 180 | body .ss { color: #19469D } /* Literal.String.Symbol */ 181 | body .bp { color: #954121 } /* Name.Builtin.Pseudo */ 182 | body .vc { color: #19469D } /* Name.Variable.Class */ 183 | body .vg { color: #19469D } /* Name.Variable.Global */ 184 | body .vi { color: #19469D } /* Name.Variable.Instance */ 185 | body .il { color: #666666 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | nytimes-style.rb 6 | 7 | 8 | 9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 26 | 30 | 31 | 32 | 39 | 44 | 45 | 46 | 58 | 67 | 68 | 69 | 80 | 99 | 100 | 101 | 111 | 120 | 121 | 122 | 134 | 161 | 162 |

nytimes-style.rb

21 |
22 | 23 |
24 | 25 |
27 |
require 'date'
 28 | require 'yaml'
29 |
33 |
34 | 35 |
36 |

A small set of helper methods for generating text that conforms to The New York Times Manual of Style and Usage, 37 | hosted on Github.

38 |
40 |
module Nytimes
 41 |   module Style
 42 |     
43 |
47 |
48 | 49 |
50 |
51 |

“In general, spell out the first nine cardinal and 52 | ordinal numbers [but] spell any number that begins a sentence…” 53 | Exceptions include “ages of people 54 | and animals,” “sums of money,” “degrees of temperature” and “mentions of the Twelve 55 | Apostles and the Ten Commandments.”

56 |
57 |
59 |
    def nytimes_number(n)
 60 |       if n < 10
 61 |         %w(one two three four five six seven eight nine)[n - 1]
 62 |       else
 63 |         n.to_s
 64 |       end
 65 |     end
66 |
70 |
71 | 72 |
73 |
74 |

“Abbreviate the names of months from August through 75 | February in news copy when they are followed by numerals: Aug. 1; Sept. 76 | 2; Oct. 3; Nov. 4; Dec. 5; Jan. 6; Feb. 7. Do not abbreviate March, 77 | April, May, June and July except as a last resort in a chart or table.”

78 |
79 |
81 |
    def nytimes_date(date, opts={})
 82 |       str = ""
 83 |       str << date.strftime('%A, ') if opts[:day_of_week]
 84 |       str << nytimes_month_and_day(date)
 85 |       str << ", #{date.year}" unless opts[:hide_current_year] && date.year == Date.today.year
 86 |       return str
 87 |     end
 88 |     
 89 |     def nytimes_month_and_day(date)
 90 |       "#{nytimes_month date.month} #{date.day}"
 91 |     end
 92 |     
 93 |     def nytimes_month(month)
 94 |       raise ArgumentError.new "Unknown month: #{month}" unless (1..12).include? month
 95 |       %w(Jan. Feb. March April May June July Aug. Sept. Oct. Nov. Dec.)[month - 1]
 96 |     end
 97 |     
98 |
102 |
103 | 104 |
105 |
106 |

“Use numerals in giving clock time: 10:30 a.m.; 10:30. 107 | Do not use half-past 10 except in a direct quotation. 108 | Also avoid the redundant 10:30 a.m. yesterday morning and Monday afternoon at 2 p.m.”

109 |
110 |
112 |
    def nytimes_time(time, opts={})
113 |       raise ArgumentError.new "Time or DateTime required" unless time.class == DateTime || time.class == Time
114 |       str = ""
115 |       str << time.strftime("%l:%M").strip
116 |       str << time.strftime(" %p").sub('PM','p.m.').sub('AM','a.m.') unless opts[:hide_abbreviation]
117 |       str
118 |     end
119 |
123 |
124 | 125 |
126 |
127 |

“The abbreviation to be used for each state, after the names of cities, 128 | towns and counties… Use no 129 | spaces between initials like N.H. Do not abbreviate Alaska, Hawaii, Idaho, 130 | Iowa, Ohio and Utah. (Do not ordinarily use the Postal Service’s 131 | two-letter abbreviations; some are hard to tell apart on quick reading.)”

132 |
133 |
135 |
    def nytimes_state_abbrev(state_name_or_code)
136 |       state = states[state_name_or_code]
137 |       raise ArgumentError.new "Unknown postal code, state name or FIPS code: #{state_name_or_code}" unless state
138 |       state['nytimes_abbrev']
139 |     end
140 |     
141 |     def nytimes_state_name(state_abbrev_or_code)
142 |       state = states[state_abbrev_or_code]
143 |       raise ArgumentError.new "Unknown postal code, abbreviation or FIPS code: #{state_abbrev_or_code}" unless state
144 |       state['name']
145 |     end
146 |     
147 |     private
148 | 
149 |     STATE_DATA_FILE = File.join(File.dirname(__FILE__), 'nytimes-style/states.yml')
150 | 
151 |     def states
152 |       @states ||= YAML::load(File.open(STATE_DATA_FILE)).inject({}) do |h, state|
153 |         h.merge({ state['postal_code'] => state, state['name'] => state, state['fips_code'] => state })
154 |       end
155 |     end
156 |     
157 | 
158 |   end
159 | end
160 |
163 |
164 | 165 | --------------------------------------------------------------------------------