two_chainz 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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