spicy-proton 1.0.0 → 1.1.0

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.
@@ -0,0 +1,103 @@
1
+ require 'yaml'
2
+ require 'bindata'
3
+ require 'seek'
4
+
5
+ module Spicy
6
+ end
7
+
8
+ module Spicy::Disk
9
+ module Files
10
+ def self.dir
11
+ @@dir ||= File.join(File.dirname(__FILE__), 'corpus')
12
+ end
13
+
14
+ def self.adjectives
15
+ @@adjectives ||= File.join(dir, 'adjectives.bin')
16
+ end
17
+
18
+ def self.nouns
19
+ @@nouns ||= File.join(dir, 'nouns.bin')
20
+ end
21
+
22
+ def self.colors
23
+ @@colors ||= File.join(dir, 'colors.bin')
24
+ end
25
+ end
26
+
27
+ class Header < BinData::Record
28
+ endian :little
29
+ uint8 :width
30
+ uint8 :min_length
31
+ uint8 :group_count, :value => lambda { cumulative.length }
32
+ array :cumulative, :type => :uint32, :initial_length => :group_count
33
+ end
34
+
35
+ class WordList
36
+ include Spicy::Seek
37
+
38
+ def initialize(file_name)
39
+ @file = File.open(file_name, 'r')
40
+ header = Header.read(@file)
41
+ @origin = @file.pos
42
+
43
+ @width = header.width.to_i
44
+ @min = header.min_length.to_i
45
+ @max = @min + header.cumulative.count - 1
46
+
47
+ @cumulative = Hash[(@min..@max).zip(header.cumulative.to_a.map(&:to_i))]
48
+ end
49
+
50
+ def close
51
+ @file.close
52
+ end
53
+
54
+ def word(*args)
55
+ self.seek(*args) do |index, _|
56
+ @file.seek(@origin + index * @width, IO::SEEK_SET)
57
+ @file.read(@width).strip
58
+ end
59
+ end
60
+ end
61
+
62
+ class Corpus
63
+ private_class_method :new
64
+
65
+ def self.use
66
+ corpus = new
67
+ begin
68
+ yield corpus
69
+ ensure
70
+ corpus.close
71
+ end
72
+ end
73
+
74
+ def initialize
75
+ @lists = {}
76
+ end
77
+
78
+ def close
79
+ @lists.values.each(&:close)
80
+ end
81
+
82
+ def adjective(*args)
83
+ generate(:adjectives, *args)
84
+ end
85
+
86
+ def noun(*args)
87
+ generate(:nouns, *args)
88
+ end
89
+
90
+ def color(*args)
91
+ generate(:colors, *args)
92
+ end
93
+
94
+ private
95
+
96
+ def generate(type, *args)
97
+ @lists[type] ||= begin
98
+ WordList.new(Files.send(type))
99
+ end
100
+ @lists[type].word(*args)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,71 @@
1
+ require 'yaml'
2
+ require 'seek'
3
+
4
+ module Spicy
5
+ end
6
+
7
+ module Spicy::Memory
8
+ module Files
9
+ def self.dir
10
+ @@dir ||= File.join(File.dirname(__FILE__), 'corpus')
11
+ end
12
+
13
+ def self.adjectives
14
+ @@adjectives ||= File.join(dir, 'adjectives.yaml')
15
+ end
16
+
17
+ def self.nouns
18
+ @@nouns ||= File.join(dir, 'nouns.yaml')
19
+ end
20
+
21
+ def self.colors
22
+ @@colors ||= File.join(dir, 'colors.yaml')
23
+ end
24
+ end
25
+
26
+ class WordList
27
+ include Spicy::Seek
28
+
29
+ def initialize(file_name)
30
+ dataset = YAML.load_file(file_name)
31
+
32
+ @words = dataset['words']
33
+ @cumulative = dataset['cumulative']
34
+
35
+ @min = @cumulative.keys.min
36
+ @max = @cumulative.keys.max
37
+ end
38
+
39
+ def word(*args)
40
+ self.seek(*args) do |index, length|
41
+ index -= (@cumulative[length - 1] || 0)
42
+ @words[length][index]
43
+ end
44
+ end
45
+ end
46
+
47
+ class Corpus
48
+ def initialize
49
+ dir = File.dirname(__FILE__)
50
+ @adjectives = WordList.new(Files.adjectives)
51
+ @nouns = WordList.new(Files.nouns)
52
+ @colors = WordList.new(Files.colors)
53
+ end
54
+
55
+ def adjective(*args)
56
+ @adjectives.word(*args)
57
+ end
58
+
59
+ def noun(*args)
60
+ @nouns.word(*args)
61
+ end
62
+
63
+ def color(*args)
64
+ @colors.word(*args)
65
+ end
66
+
67
+ def pair(separator = '-')
68
+ "#{self.adjective}#{separator}#{self.noun}"
69
+ end
70
+ end
71
+ end
data/lib/seek.rb ADDED
@@ -0,0 +1,30 @@
1
+ require 'securerandom'
2
+
3
+ module Spicy
4
+ module Seek
5
+ def seek(min: nil, max: nil, length: nil, &found)
6
+ if !length.nil? && (!min.nil? || !max.nil?)
7
+ raise ArgumentError.new('length cannot be specified if min or max are specified.')
8
+ end
9
+
10
+ if !min.nil? && !max.nil? && min > max
11
+ raise ArgumentError.new('min must be no more than max.')
12
+ end
13
+
14
+ min = [min || length || @min, @min].max
15
+ max = [max || length || @max, @max].min
16
+
17
+ rand_min = @cumulative[min - 1] || 0
18
+ rand_max = @cumulative[max] || @cumulative[@max]
19
+ index = SecureRandom.random_number(rand_min...rand_max)
20
+
21
+ min.upto(max) do |len|
22
+ if @cumulative[len] > index
23
+ return found.call(index, len)
24
+ end
25
+ end
26
+
27
+ nil
28
+ end
29
+ end
30
+ end
data/lib/spicy-proton.rb CHANGED
@@ -1,66 +1,55 @@
1
- require 'yaml'
2
- require 'binary'
3
- require 'files'
1
+ require 'forwardable'
2
+ require 'disk-corpus'
3
+ require 'memory-corpus'
4
4
 
5
5
  module Spicy
6
6
  class Proton
7
+ extend Forwardable
8
+
7
9
  def initialize
8
- dir = File.dirname(__FILE__)
9
- @adjectives = YAML.load_file(Files.adjectives)
10
- @nouns = YAML.load_file(Files.nouns)
11
- @colors = YAML.load_file(Files.colors)
10
+ @corpus = Memory::Corpus.new
12
11
  end
13
12
 
14
- def self.adjective
15
- BinaryCorpus.use(&:adjective)
13
+ def self.adjective(*args)
14
+ Disk::Corpus.use do |c|
15
+ c.adjective(*args)
16
+ end
16
17
  end
17
18
 
18
- def self.noun
19
- BinaryCorpus.use(&:noun)
19
+ def self.noun(*args)
20
+ Disk::Corpus.use do |c|
21
+ c.noun(*args)
22
+ end
20
23
  end
21
24
 
22
- def self.color
23
- BinaryCorpus.use(&:color)
25
+ def self.color(*args)
26
+ Disk::Corpus.use do |c|
27
+ c.color(*args)
28
+ end
24
29
  end
25
30
 
26
31
  def self.pair(separator = '-')
27
- BinaryCorpus.use do |b|
28
- "#{b.adjective}#{separator}#{b.noun}"
32
+ Disk::Corpus.use do |c|
33
+ "#{c.adjective}#{separator}#{c.noun}"
29
34
  end
30
35
  end
31
36
 
32
37
  def self.format(format)
33
- BinaryCorpus.use do |b|
34
- self.format_with(b, format)
38
+ Disk::Corpus.use do |c|
39
+ self.format_with(c, format)
35
40
  end
36
41
  end
37
42
 
38
- def adjective
39
- random(adjectives)
40
- end
41
-
42
- def noun
43
- random(nouns)
44
- end
45
-
46
- def color
47
- random(colors)
48
- end
49
-
50
- def pair(separator = '-')
51
- "#{self.adjective}#{separator}#{self.noun}"
52
- end
53
-
54
43
  def format(format)
55
44
  self.class.format_with(self, format)
56
45
  end
57
46
 
58
- attr_accessor :adjectives, :nouns, :colors
47
+ def_delegators :@corpus, :adjective, :noun, :color, :pair, :adjectives, :nouns, :colors
59
48
 
60
49
  private
61
50
 
62
51
  def self.format_with(source, format)
63
- format.gsub(/%([anc])/) do
52
+ format.gsub(/%([anc%])/) do
64
53
  case $1
65
54
  when 'a'
66
55
  source.adjective
@@ -68,13 +57,10 @@ module Spicy
68
57
  source.noun
69
58
  when 'c'
70
59
  source.color
60
+ when '%'
61
+ '%'
71
62
  end
72
63
  end
73
64
  end
74
-
75
- def random(set)
76
- index = SecureRandom.random_number(set.count)
77
- set[index]
78
- end
79
65
  end
80
66
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spicy-proton
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Schmich
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-01-29 00:00:00.000000000 Z
11
+ date: 2017-01-30 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bindata
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.3'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: minitest
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -32,12 +46,15 @@ extra_rdoc_files: []
32
46
  files:
33
47
  - LICENSE
34
48
  - README.md
35
- - lib/binary.rb
49
+ - lib/corpus/adjectives.bin
36
50
  - lib/corpus/adjectives.yaml
51
+ - lib/corpus/colors.bin
37
52
  - lib/corpus/colors.yaml
38
- - lib/corpus/combined.bin
53
+ - lib/corpus/nouns.bin
39
54
  - lib/corpus/nouns.yaml
40
- - lib/files.rb
55
+ - lib/disk-corpus.rb
56
+ - lib/memory-corpus.rb
57
+ - lib/seek.rb
41
58
  - lib/spicy-proton.rb
42
59
  homepage: https://github.com/schmich/spicy-proton
43
60
  licenses:
@@ -51,7 +68,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
51
68
  requirements:
52
69
  - - ">="
53
70
  - !ruby/object:Gem::Version
54
- version: 1.9.3
71
+ version: 2.0.0
55
72
  required_rubygems_version: !ruby/object:Gem::Requirement
56
73
  requirements:
57
74
  - - ">="
data/lib/binary.rb DELETED
@@ -1,102 +0,0 @@
1
- require 'json'
2
- require 'yaml'
3
- require 'securerandom'
4
- require 'files'
5
-
6
- module Spicy
7
- class BinaryCorpus
8
- private_class_method :new
9
-
10
- def self.use
11
- file = File.open(Files.combined, 'r')
12
- begin
13
- corpus = new(file)
14
- yield corpus
15
- ensure
16
- file.close
17
- end
18
- end
19
-
20
- def initialize(file)
21
- @file = file
22
- @meta = {}
23
- self.class.corpus.keys.each do |set|
24
- bytes = @file.read(3 * 4)
25
- start, count, size = bytes.unpack('L*')
26
- @meta[set] = {
27
- start: start,
28
- count: count,
29
- size: size
30
- }
31
- end
32
- end
33
-
34
- def self.generate
35
- dir = File.dirname(__FILE__)
36
- sources = corpus.values
37
-
38
- sets = sources.map do |source|
39
- terms = YAML.load_file(source)
40
- {
41
- terms: terms,
42
- start: 0,
43
- count: terms.count,
44
- size: terms.map(&:length).max
45
- }
46
- end
47
-
48
- start = (3 * 4) * sets.length
49
- sets.each do |set|
50
- set[:start] = start
51
- start += set[:count] * set[:size]
52
- end
53
-
54
- File.open(Files.combined, 'w+') do |f|
55
- meta = []
56
- sets.each do |set|
57
- meta << set[:start]
58
- meta << set[:count]
59
- meta << set[:size]
60
- end
61
-
62
- f.write(meta.pack('L*'))
63
-
64
- sets.each do |set|
65
- set[:terms].each do |term|
66
- padding = "\0" * (set[:size] - term.length)
67
- f.write(term + padding)
68
- end
69
- end
70
- end
71
- end
72
-
73
- def adjective
74
- read_random(:adjectives)
75
- end
76
-
77
- def noun
78
- read_random(:nouns)
79
- end
80
-
81
- def color
82
- read_random(:colors)
83
- end
84
-
85
- private
86
-
87
- def read_random(set)
88
- set = @meta[set]
89
- index = SecureRandom.random_number(set[:count])
90
- @file.seek(set[:start] + index * set[:size], IO::SEEK_SET)
91
- @file.read(set[:size]).strip
92
- end
93
-
94
- def self.corpus
95
- {
96
- adjectives: Files.adjectives,
97
- nouns: Files.nouns,
98
- colors: Files.colors
99
- }
100
- end
101
- end
102
- end