feminizer 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in feminizer.gemspec
4
+ gemspec
data/README.markdown ADDED
@@ -0,0 +1,9 @@
1
+ # Feminizer
2
+
3
+ Turns men into women and women into men. Great for a mind-fuck or to prove an example of implicity patriarchy.
4
+ In use at [The Art Of Womanliness](http://artofwomanliness.heroku.com/).
5
+
6
+
7
+ Patches welcome, forks celebrated.
8
+
9
+ Copyright (c) 2011 [Jack Danger Canty](http://jåck.com). Released under the MIT License.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
3
+
4
+ task :default => :test
5
+
6
+ require 'rake/testtask'
7
+ Rake::TestTask.new(:test) do |test|
8
+ test.libs << '.'
9
+ test.ruby_opts << '-rubygems'
10
+ test.pattern = 'test/*.rb'
11
+ test.verbose = true
12
+ end
data/feminizer.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "feminizer"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "feminizer"
7
+ s.version = Feminizer::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Jack Danger Canty"]
10
+ s.email = ["rubygems@6brand.com"]
11
+ s.homepage = "http://github.com/JackDanger/feminizer"
12
+ s.summary = %q{Programmatically swap the gender of an English text string}
13
+ s.description = %q{This library can take a piece of English text as a string and swap masculine words for feminine and vice-versa.}
14
+
15
+ s.rubyforge_project = "feminizer"
16
+
17
+ s.add_dependency 'nokogiri'
18
+ s.add_dependency 'activesupport'
19
+ s.add_dependency 'without_accents'
20
+ s.add_development_dependency 'shoulda'
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
+ s.require_paths = ["lib"]
26
+ end
data/lib/feminizer.rb ADDED
@@ -0,0 +1,144 @@
1
+ require 'without_accents'
2
+ require 'nokogiri'
3
+
4
+ module Feminizer
5
+
6
+ VERSION = "1.0.1"
7
+
8
+
9
+ extend self
10
+
11
+ def feminize_html content
12
+ tree = Nokogiri::HTML content
13
+ feminize_node! tree
14
+ tree.to_html
15
+ end
16
+
17
+ def feminize_text string
18
+ return string if ['', '\n', "\n"].include?(string.to_s)
19
+
20
+ string = string.dup.without_accents
21
+ string = string.gsub(/\302\240/, ' ')
22
+
23
+
24
+ forms = {
25
+ 'man' => 'woman',
26
+ 'men' => 'women',
27
+ 'manly' => 'womanly',
28
+ 'manliness' => 'womanliness',
29
+ 'manlier' => 'womanlier',
30
+ 'manliest' => 'womanliest',
31
+ 'manhood' => 'womanhood',
32
+ 'manvotional' => 'womanvotional',
33
+ 'masculine' => 'feminine',
34
+ 'masculinity' => 'femininity',
35
+ 'male' => 'female',
36
+ 'patriarch' => 'matriarch',
37
+ 'mr.' => 'ms.',
38
+ 'boy' => 'girl',
39
+ 'boys' => 'girls',
40
+ 'guy' => 'gal',
41
+ 'guys' => 'gals',
42
+ 'dude' => 'lady',
43
+ 'dudes' => 'ladies',
44
+ 'he' => 'she',
45
+ 'his' => 'her',
46
+ 'him' => 'her',
47
+ 'himself' => 'herself',
48
+ 'waitress' => 'waiter',
49
+ 'waitressed' => 'waited',
50
+ 'craftsman' => 'craftswoman',
51
+ 'nobleman' => 'noblewoman',
52
+ 'gentleman' => 'lady',
53
+ 'gentlemen' => 'ladies',
54
+ 'prince' => 'princess',
55
+ 'princes' => 'princesses',
56
+ 'king' => 'queen',
57
+ 'kings' => 'queens',
58
+ 'sissy' => 'boyish',
59
+ 'emasculate' => 'defeminize',
60
+ 'cowboy' => 'cowgirl',
61
+ 'cowboying' => 'cowgirling',
62
+ 'cowboys' => 'cowgirls',
63
+ 'dad' => 'mom',
64
+ 'daddy' => 'mommy',
65
+ 'dick' => 'pussy',
66
+ 'ex-wife' => 'ex-husband',
67
+ 'father' => 'mother',
68
+ 'fathers' => 'mothers',
69
+ 'brother' => 'sister',
70
+ 'brothers' => 'sisters',
71
+ 'Matt' => 'Mattie',
72
+ 'David' => 'Davida',
73
+ 'Paul' => 'Paula'
74
+ }
75
+
76
+ forms.each do |masculine, feminine|
77
+ if string =~ /#{feminine}/i
78
+ string = string_search_replace(string, feminine, masculine, :mark) unless 'his' == masculine
79
+ string = string_search_replace(string, masculine, feminine)
80
+ string = string_search_replace(string, feminine, masculine, :unmark) unless 'his' == masculine
81
+ elsif string =~ /#{masculine}/i
82
+ string = string_search_replace(string, masculine, feminine)
83
+ end
84
+ end
85
+
86
+ string
87
+ end
88
+
89
+ protected
90
+
91
+ def feminize_node! node, indent = 0
92
+ case node.name
93
+ when 'text'
94
+ # print " "*indent
95
+ # puts "feminizing: #{node.content.inspect}"
96
+ node.content = feminize_text(node.content)
97
+ # print " "*indent
98
+ # puts "out: #{node.content.inspect}"
99
+ when 'a'
100
+ # puts "rewriting: #{node.attributes['href'].value}"
101
+ if href = node.attributes['href']
102
+ href.value = href.value.sub(/https?:\/\/artofmanliness.com\/?/, '/')
103
+ end
104
+ else
105
+ # puts 'not processing: '+node.inspect
106
+ end
107
+
108
+ if node.children.size > 0
109
+ node.children.each do |child|
110
+ # print " "*indent
111
+ # puts "-> #{child.name}"
112
+ feminize_node! child, indent + 1
113
+ end
114
+ end
115
+ end
116
+
117
+
118
+ def ok
119
+ @ok ||= %Q{([\s"':;\.,\>\<\?\!-])}
120
+ end
121
+
122
+ def string_search_replace(string, from, to, mode = nil)
123
+ [
124
+ [ from, to],
125
+ [ from[0..0].upcase + from[1..-1],
126
+ to[0..0].upcase + to[1..-1] ]
127
+ ].each do |search, replace|
128
+ case mode
129
+ when :mark
130
+ replace = "[marked]#{search}[marked]"
131
+ when :unmark
132
+ search = /\[marked\]#{search}\[marked\]/
133
+ end
134
+
135
+ string.gsub! %r{#{ok}#{search}#{ok}}, '\1'+replace+'\2'
136
+ string.gsub! %r{^#{search}#{ok}}, replace+'\1'
137
+ string.gsub! %r{#{ok}#{search}$}, '\1'+replace
138
+ string.gsub! %r{^#{search}$}, replace
139
+
140
+ end
141
+ string
142
+ end
143
+
144
+ end
@@ -0,0 +1,151 @@
1
+ require 'test/unit'
2
+ require 'active_support'
3
+ require 'open-uri'
4
+ require File.expand_path File.join(File.dirname(__FILE__), '..', 'lib', 'feminizer')
5
+ require 'shoulda'
6
+
7
+ class FeminizerTest < Test::Unit::TestCase
8
+ def feminize_text *args
9
+ Feminizer.feminize_text *args
10
+ end
11
+ def feminize_html *args
12
+ Feminizer.feminize_html *args
13
+ end
14
+
15
+ context "feminize_text" do
16
+ setup {
17
+ @feminized = feminize_text "The Art of Manliness - by a Man’s man, as his hobby, for masculine men everywhere"
18
+ }
19
+ should "turn all girly" do
20
+ assert_equal "The Art of Womanliness - by a Woman's woman, as her hobby, for feminine women everywhere",
21
+ @feminized
22
+ end
23
+ end
24
+ context "feminize" do
25
+ setup {
26
+ @feminized = feminize_html HTML.dup
27
+ }
28
+ should "have remote url in original" do
29
+ assert_match %r{<li><a href="http://artofmanliness.com/man-knowledge">Man Knowledge</a></li>}, HTML
30
+ end
31
+ should "replace link content with feminized text and relative path" do
32
+ assert_match %r{<li><a href="/man-knowledge">Woman Knowledge</a></li>}, @feminized
33
+ end
34
+ should "replace link content when it's next to an image" do
35
+ assert_match %r{How to Apologize Like a Woman}, @feminized
36
+ end
37
+ should "swap genders in small string" do
38
+ assert_match %r{This string started with Man in it and should turn into Woman},
39
+ feminize_html("This string started with Woman in it and should turn into Man")
40
+ end
41
+ should "swap genders in full document" do
42
+ assert_match %r{This string started with Man in it and should turn into Woman}, @feminized
43
+ end
44
+ should "feminize even if a period is following the word" do
45
+ assert_match %r{would be the cowgirl.},
46
+ feminize_html(open("http://artofmanliness.com/2010/09/07/3-archetypes-of-american-manliness-part-ii-the-heroic-artisan/", {'User-Agent' => 'Firefox'}).read)
47
+ end
48
+ end
49
+
50
+
51
+ HTML = <<-EOHTML
52
+ <html xmlns="http://www.w3.org/1999/xhtml" xmlns:og="http://opengraphprotocol.org/schema/" xmlns:fb="http://www.facebook.com/2008/fbml" dir="ltr" lang="en-US">
53
+ <head profile="http://gmpg.org/xfn/11">
54
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
55
+ <title>The Art of Manliness | Men&#039;s Interests and Lifestyle</title>
56
+ <meta name="robots" content="noodp, noydir" />
57
+ <meta name="description" content="The Art of Manliness is a men\&#8217;s interest and lifestyle site dedicated to reviving the lost art of manliness." />
58
+ <meta name="keywords" content="men, man, manliness," />
59
+ <link rel="stylesheet" href="http://artofmanliness.com/wp-content/themes/thesis_18/style.css?081310-141114" type="text/css" media="screen, projection" />
60
+ <link rel="stylesheet" href="http://artofmanliness.com/wp-content/themes/thesis_18/custom/layout.css?082310-12445" type="text/css" media="screen, projection" />
61
+ <!--[if lte IE 8]><link rel="stylesheet" href="http://artofmanliness.com/wp-content/themes/thesis_18/lib/css/ie.css?072510-23516" type="text/css" media="screen, projection" /><![endif]-->
62
+ <link rel="stylesheet" href="http://artofmanliness.com/wp-content/themes/thesis_18/custom/custom.css?091610-211116" type="text/css" media="screen, projection" />
63
+ <link rel="canonical" href="http://artofmanliness.com/" />
64
+ <link rel="alternate" type="application/rss+xml" title="The Art of Manliness RSS Feed" href="http://feeds2.feedburner.com/TheArtOfManliness" />
65
+ <link rel="pingback" href="http://artofmanliness.com/xmlrpc.php" />
66
+ <link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://artofmanliness.com/xmlrpc.php?rsd" />
67
+ <script language="Javascript">
68
+ <!--
69
+ var axel = Math.random() + "";
70
+ var ord = axel * 1000000000000000000;
71
+ //-->
72
+ </script>
73
+ <!-- PUT THIS TAG IN THE head SECTION -->
74
+ <script type="text/javascript" src="http://partner.googleadservices.com/gampad/google_service.js">
75
+ </script>
76
+ <script type="text/javascript">
77
+ GS_googleAddAdSenseService("ca-pub-5284223420088782");
78
+ GS_googleEnableAllServices();
79
+ </script>
80
+ <script type="text/javascript">
81
+ GA_googleAddSlot("ca-pub-5284223420088782", "300x105");
82
+ </script>
83
+ <script type="text/javascript">
84
+ GA_googleFetchAds();
85
+ </script>
86
+ <!-- END OF TAG FOR head SECTION -->
87
+ <script type="text/javascript">
88
+ (function() {
89
+ var s = document.createElement('SCRIPT'), s1 = document.getElementsByTagName('SCRIPT')[0];
90
+ s.type = 'text/javascript';
91
+ s.src = 'http://widgets.digg.com/buttons.js';
92
+ s1.parentNode.insertBefore(s, s1);
93
+ })();
94
+ </script>
95
+ <script type="text/javascript">var _sf_startpt=(new Date()).getTime()</script>
96
+ <meta name="verify-postrank" content="7pljxog" />
97
+ <link rel='stylesheet' id='slideshow-gallery-css' href='http://artofmanliness.com/wp-content/plugins/slideshow-gallery/css/gallery-css.php?1=1&amp;resizeimages=Y&amp;width=618&amp;height=336&amp;border&amp;background=%23000000&amp;infobackground=%23000000&amp;infocolor=%23FFFFFF&#038;ver=1.0' type='text/css' media='screen' />
98
+ <link rel='stylesheet' id='wp-email-css' href='http://artofmanliness.com/wp-content/plugins/wp-email/email-css.css?ver=2.50' type='text/css' media='all' />
99
+ <script type='text/javascript' src='http://artofmanliness.com/wp-includes/js/jquery/jquery.js?ver=1.4.2'></script>
100
+ <script type='text/javascript' src='http://artofmanliness.com/wp-content/plugins/slideshow-gallery/js/gallery.js?ver=1.0'></script>
101
+ <meta property="fb:admins" content="9604892"/><meta property="og:site_name" content="The Art of Manliness"/><meta property="og:url" content="http://artofmanliness.com/"/><meta property="og:type" content="blog"/><!-- tweet this -->
102
+ <!-- End tweet this -->
103
+
104
+ <link rel=”shortcut icon” href=”http://artofmanliness.com/favicon.ico”>
105
+ <meta name="verify-v1" content="4RSETFIMUwgS0VJ1XssuMNE1blUbrfpZHAb6qTSZde0=" >
106
+ <style type="text/css">
107
+ ol.footnotes li {list-style-type:decimal;}
108
+ ol.footnotes{font-size:0.8em; color:#666666;} </style>
109
+ </head>
110
+ <body class="custom">
111
+ <div id="header_area" class="full_width">
112
+ <div class="page">
113
+ <div id="topad">
114
+ <!-- FM Leaderboard 1 Zone -->
115
+ <script type='text/javascript' src='http://static.fmpub.net/zone/3323'></script>
116
+ <!-- FM Leaderboard 1 Zone -->
117
+ </div> <div id="header">
118
+ <p id="logo"><a href="http://artofmanliness.com">The Art of Manliness</a></p>
119
+ <h1 id="tagline">Men&#039;s Interests and Lifestyle</h1>
120
+ </div>
121
+ <ul class="menu">
122
+ <li class="tab tab-home current"><a href="http://artofmanliness.com" rel="nofollow">Home</a></li>
123
+ <li class="cat-item cat-item-3"><a href="http://artofmanliness.com/category/a-mans-life/" title="View all posts filed under A Man&#039;s Life">A Man&#039;s Life</a>
124
+ </li>
125
+ <li class="cat-item cat-item-5"><a href="http://artofmanliness.com/category/dress-grooming/" title="View all posts filed under Dress &amp; Grooming">Dress &amp; Grooming</a>
126
+ </li>
127
+ <li class="cat-item cat-item-7"><a href="http://artofmanliness.com/category/health-sports/" title="View all posts filed under Health &amp; Sports">Health &amp; Sports</a>
128
+ </li>
129
+ <li class="cat-item cat-item-11"><a href="http://artofmanliness.com/category/manly-skills/" title="View all posts filed under Manly Skills">Manly Skills</a>
130
+ </li>
131
+ <li class="cat-item cat-item-12"><a href="http://artofmanliness.com/category/money-career/" title="View all posts filed under Money &amp; Career">Money &amp; Career</a>
132
+ </li>
133
+ <li class="cat-item cat-item-65"><a href="http://artofmanliness.com/category/relationships-family/" title="View all posts filed under Relationships &amp; Family">Relationships &amp; Family</a>
134
+ </li>
135
+ <li><a href="http://community.artofmanliness.com">Community</a></li>
136
+ <li><a href="http://artofmanliness.com/man-knowledge">Man Knowledge</a></li>
137
+ </ul>
138
+ </div>
139
+ </div>
140
+ </div>
141
+ <span>This string started with Woman in it and should turn into Man</span>
142
+ <span>I love me that cowboy.</span>
143
+ <a href="/2009/08/23/how-to-apologize-like-a-man/" rel="bookmark">
144
+ <img src="http://content.artofmanliness.com/uploads/2009/thumbnails/apologizethumb.jpg" alt="How to Apologize Like a Man">
145
+ How to Apologize Like a Man
146
+ </a>
147
+ </body>
148
+ </html>
149
+ EOHTML
150
+
151
+ end
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: feminizer
3
+ version: !ruby/object:Gem::Version
4
+ hash: 21
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 1
10
+ version: 1.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jack Danger Canty
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-01-28 00:00:00 -08:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: nokogiri
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: activesupport
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: without_accents
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ - !ruby/object:Gem::Dependency
64
+ name: shoulda
65
+ prerelease: false
66
+ requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ hash: 3
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ version_requirements: *id004
77
+ description: This library can take a piece of English text as a string and swap masculine words for feminine and vice-versa.
78
+ email:
79
+ - rubygems@6brand.com
80
+ executables: []
81
+
82
+ extensions: []
83
+
84
+ extra_rdoc_files: []
85
+
86
+ files:
87
+ - .gitignore
88
+ - Gemfile
89
+ - README.markdown
90
+ - Rakefile
91
+ - feminizer.gemspec
92
+ - lib/feminizer.rb
93
+ - test/feminizer_test.rb
94
+ has_rdoc: true
95
+ homepage: http://github.com/JackDanger/feminizer
96
+ licenses: []
97
+
98
+ post_install_message:
99
+ rdoc_options: []
100
+
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
111
+ version: "0"
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ requirements: []
122
+
123
+ rubyforge_project: feminizer
124
+ rubygems_version: 1.3.7
125
+ signing_key:
126
+ specification_version: 3
127
+ summary: Programmatically swap the gender of an English text string
128
+ test_files:
129
+ - test/feminizer_test.rb