two_chainz 0.0.0 → 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright 2013 Jake Boxer
2
+ http://jakeboxer.com/
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Two Chainz
2
+
3
+ > She got a big booty so I call her Big Booty
4
+ > Scrr... scrr... wrists moving, cooking, getting to it
5
+ > I'm in the kitchen, yams everywhere
6
+ > Just made a jug, I got bands everywhere
7
+ >
8
+ – [2 Chainz - Birthday Song](http://rapgenius.com/2-chainz-birthday-song-lyrics) (which was generated entirely with this gem)
9
+
10
+ **Two Chainz** is a Ruby gem for generating random sentences with [Markov chains](http://en.wikipedia.org/wiki/Markov_chain).
11
+
12
+ ## Quickstart
13
+
14
+ ``` ruby
15
+ require 'two_chainz'
16
+
17
+ generator = TwoChainz::Generator.new
18
+
19
+ generator.hear("We just want the credit where it's due")
20
+ generator.hear("Imma worry bout me, give a fuck about you")
21
+ generator.hear("Just as a reminder to myself")
22
+ generator.hear("I wear every single chain even when I'm in the house")
23
+
24
+ generator.spit(:words => 12) # => "We just as a fuck chain even when I'm in the credit"
25
+ ```
26
+
27
+ ## Less important shit
28
+
29
+ If you instantiate the generator normally, spitting will be random.
30
+
31
+ ``` ruby
32
+ generator = TwoChainz::Generator.new
33
+
34
+ generator.hear("I love you I love you")
35
+ generator.hear("You are alright I guess")
36
+
37
+ generator.spit(:words => 2) # => "I guess"
38
+ generator.spit(:words => 2) # => "You I"
39
+ ```
40
+
41
+ You can seed the generator if you want consistency.
42
+
43
+ ``` ruby
44
+ generator = TwoChainz::Generator.new(:seed => 3)
45
+ ```
46
+
47
+ If you want even more consistency, run it in boring mode. This will always continue the chain the same way: the most common next word is picked every time, and the alphabetically-first word is picked if there's a tie.
48
+
49
+ ``` ruby
50
+ generator = TwoChainz::Generator.new(:boring => true)
51
+
52
+ generator.hear("I love you I love you I love you")
53
+ generator.hear("You are alright I guess")
54
+
55
+ generator.spit(:words => 2) # => "I love"
56
+ generator.spit(:words => 2) # => "I love"
57
+ ```
58
+
59
+ Instead of specifying how many words you want, you can specify a maximum number of characters. You'll get a sentence that is guaranteed to be that many characters or fewer (and it will usually come pretty close).
60
+
61
+ ``` ruby
62
+ generator = TwoChainz::Generator.new
63
+
64
+ generator.hear("Once they caught us off-guard")
65
+ generator.hear("The Mac-10 was in the grass and")
66
+ generator.hear("I ran like a cheetah with thoughts of an assassin")
67
+
68
+ generator.spit(:max_chars => 20) # => "Once they cheetah"
69
+ ```
data/lib/two_chainz.rb CHANGED
@@ -1,5 +1,2 @@
1
- class TwoChainz
2
- def self.hi
3
- puts "Hello world!"
4
- end
5
- end
1
+ require 'two_chainz/generator'
2
+ require 'two_chainz/words_table'
@@ -0,0 +1,110 @@
1
+ class TwoChainz::Generator
2
+ # Public: Create a new TwoChainz::Generator instance.
3
+ #
4
+ # options - Hash of options.
5
+ # :seed - (Optional integer) Seed to use when spitting. If nothing
6
+ # is provided, Ruby core's Random::new_seed will be used.
7
+ # :boring - (Optional boolean) Don't do any randomness. Always pick
8
+ # the most common thing. Mainly for testing. Defaults to
9
+ # false.
10
+ #
11
+ # Returns a TwoChainz::Generator
12
+ def initialize(options={})
13
+ @words_table = TwoChainz::WordsTable.new
14
+
15
+ unless options[:boring]
16
+ seed = options[:seed]
17
+ @random = seed ? Random.new(seed) : Random.new
18
+ end
19
+ end
20
+
21
+ # Public: Hear some words and remember them for future spitting.
22
+ #
23
+ # words - String of words to hear.
24
+ #
25
+ # Returns the number of unique new words the generator heard (integer)
26
+ def hear(words)
27
+ heard_words = 0
28
+ previous_word = nil
29
+
30
+ words.scan(/[\w\']+/) do |current_word|
31
+ # If we haven't heard this word before, increment the newly-heard words
32
+ # count.
33
+ heard_words += 1 unless @words_table.include?(current_word)
34
+
35
+ # Increment the number of times the current word has been the successor of
36
+ # the previous word.
37
+ @words_table.increment(previous_word, current_word)
38
+
39
+ previous_word = current_word
40
+ end
41
+
42
+ # Record what the last word was.
43
+ @words_table.increment(previous_word) if previous_word
44
+
45
+ heard_words
46
+ end
47
+
48
+ # Public: Produce a randomized sentence based on the words that have been
49
+ # heard.
50
+ #
51
+ # options - Hash of options. At least one is required.
52
+ # :words - (Integer) the number of words to be generated.
53
+ # :max_chars - (Integer) the maximum number of characters to be
54
+ # generated.
55
+ #
56
+ # Returns a string.
57
+ def spit(options = {})
58
+ if @words_table.words.empty?
59
+ raise StandardError, "The generator hasn't heard anything yet"
60
+ end
61
+
62
+ words = options[:words] && Integer(options[:words])
63
+ max_chars = options[:max_chars] && Integer(options[:max_chars])
64
+
65
+ sentence = []
66
+
67
+ if words
68
+ words.times do |i|
69
+ previous_word = sentence.last || :beginning
70
+ sentence << word_after(previous_word)
71
+ end
72
+ elsif max_chars
73
+ sentence_length = -1 # Start at -1 cuz of the first space
74
+
75
+ while sentence_length < max_chars
76
+ previous_word = sentence.last || :beginning
77
+ word = word_after(previous_word)
78
+ sentence_length += word.length + 1 # Include space
79
+
80
+ sentence << word_after(previous_word) unless sentence_length > max_chars
81
+ end
82
+ else
83
+ raise ArgumentError, "Either :words or :max_chars must be specified"
84
+ end
85
+
86
+ sentence.join(' ')
87
+ end
88
+
89
+ private
90
+
91
+ # Internal: Get a word that comes after the specified one.
92
+ #
93
+ # previous_word - The word that will be coming before whichever one we pick.
94
+ #
95
+ # Returns a string.
96
+ def word_after(previous_word)
97
+ choices = @words_table.words_after(previous_word)
98
+
99
+ # Pick the most popular next word.
100
+ # TODO(jakeboxer): Make this random in non-boring situations.
101
+ next_word = choices.max_by {|word, count| count}.first
102
+
103
+ # If the most popular next word is the sentence ending, pick the
104
+ # alphabetical first word.
105
+ # TODO(jakeboxer): Make this random in non-boring situations.
106
+ next_word = heard_words.sort.first if next_word == :ending
107
+
108
+ next_word
109
+ end
110
+ end
@@ -0,0 +1,3 @@
1
+ module TwoChainz
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,79 @@
1
+ class TwoChainz::WordsTable
2
+ # Public: Create a new TwoChainz::WordsTable instance.
3
+ #
4
+ # Returns a TwoChainz::WordsTable
5
+ def initialize
6
+ # The table is a hash. Think of its entries as "rows".
7
+ # Each row is another hash. Think of its entries as "cells".
8
+ # Cells default to 0.
9
+ @table = {}
10
+ end
11
+
12
+ # Public: Increment the value in the table for the specified pair of words.
13
+ #
14
+ # first_word - The word that comes first in the pair. If this is nil, the
15
+ # second word in the pair will be recorded as the beginning of
16
+ # a sentence.
17
+ # second_word - The word that comes last in the pair. If this is nil or
18
+ # omitted, the first word in the pair will be recorded as the
19
+ # ending of a sentence.
20
+ #
21
+ # Returns the new count of the entry.
22
+ def increment(first_word=nil, second_word=nil)
23
+ # Don't do anything if we didn't get a first or second word
24
+ return 0 unless first_word || second_word
25
+
26
+ # Only one of these will run, since we error if both are nil
27
+ first_word ||= :beginning
28
+ second_word ||= :ending
29
+
30
+ add_row(first_word)
31
+ add_row(second_word) unless second_word == :ending
32
+
33
+ @table[first_word][second_word] += 1
34
+ end
35
+
36
+ # Public: Whether or not the words table has the specified word.
37
+ #
38
+ # word - Word to check for inclusion of.
39
+ #
40
+ # Returns a boolean
41
+ def include?(word)
42
+ @table.keys.include?(word)
43
+ end
44
+
45
+ # Public: Get all the words that have been incremented at least once.
46
+ #
47
+ # Returns an array.
48
+ def words
49
+ @table.keys - [:beginning]
50
+ end
51
+
52
+ # Public: Get all the words that have come after the specified word. In the
53
+ # result, the keys are the words and the values are the number of times that
54
+ # word has appeared after the specified word.
55
+ #
56
+ # Can also include the :ending key, which indicates that the sentence ended
57
+ # after that word.
58
+ #
59
+ # word - Word to find all following words for
60
+ #
61
+ # Examples
62
+ #
63
+ # increment('your', 'love')
64
+ # increment('your', 'time')
65
+ # increment('your', 'love')
66
+ # words_after('your')
67
+ # # => {"love" => 2, "time" => 1}
68
+ #
69
+ # Returns a hash.
70
+ def words_after(word)
71
+ Hash[@table[word] || {}]
72
+ end
73
+
74
+ private
75
+
76
+ def add_row(word)
77
+ @table[word] ||= Hash.new(0)
78
+ end
79
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: two_chainz
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.0
4
+ version: 0.0.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -18,7 +18,12 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - lib/two_chainz/generator.rb
22
+ - lib/two_chainz/version.rb
23
+ - lib/two_chainz/words_table.rb
21
24
  - lib/two_chainz.rb
25
+ - LICENSE
26
+ - README.md
22
27
  homepage: https://github.com/jakeboxer/two_chainz
23
28
  licenses: []
24
29
  post_install_message:
@@ -30,13 +35,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
30
35
  requirements:
31
36
  - - ! '>='
32
37
  - !ruby/object:Gem::Version
33
- version: '0'
38
+ version: 1.9.2
34
39
  required_rubygems_version: !ruby/object:Gem::Requirement
35
40
  none: false
36
41
  requirements:
37
42
  - - ! '>='
38
43
  - !ruby/object:Gem::Version
39
- version: '0'
44
+ version: 1.3.6
40
45
  requirements: []
41
46
  rubyforge_project:
42
47
  rubygems_version: 1.8.23