Skip to content

Instantly share code, notes, and snippets.

@roktas
Created January 9, 2015 01:44
Show Gist options
  • Save roktas/a29bd1acc67b643b0c8d to your computer and use it in GitHub Desktop.
Save roktas/a29bd1acc67b643b0c8d to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
# Abecesel isim üret
#
# Gereksinimler: Ruby >= 2.1, turkish_support (gem)
require 'optparse'
require 'ostruct'
require 'yaml'
require 'turkish_support'
using TurkishSupport
def die(*lines)
$stderr.puts lines.map { |line| "E: #{line}" }.join("\n")
exit 1
end
def cry(*lines)
$stderr.puts lines.map { |line| "W: #{line}" }.join("\n")
end
def log(*lines)
$stderr.puts lines.map { |line| "I: #{line}" }.join("\n")
end
class Generator # rubocop:disable Metrics/ClassLength
DICTIONARY = {
adjective: %w(
agresif
alafranga
alaturka
analog
anonim
antik
asil
avare
beklenen
belirsiz
benzersiz
bereketli
beyaz
bozuk
bulutsuz
cesur
cezbedici
ciddi
dar
dengesiz
derin
dev
dijital
dik
dogmatik
durgun
egzotik
elastik
engebeli
epik
eski
etnik
ezeli
fakir
geleneksel
geveze
gizemli
gri
grotesk
hafif
halsiz
hantal
homojen
huzurlu
ihtiyar
ilahi
ilkel
ince
iri
jenerik
kaotik
kaygan
kederli
kirli
korkutucu
kurak
kusursuz
kutsal
lacivert
lanetli
limitsiz
manyetik
masum
mavi
mekanik
mikro
mistik
monoton
mor
muhtelif
nazik
nemli
nevrotik
olgun
otomatik
parlak
patolojik
pembe
plastik
radyoaktif
rahat
ritmik
romantik
senfonik
serin
serseri
sert
sesli
sessiz
sihirli
sisli
siyah
sonsuz
tehlikeli
temiz
titrek
tombul
tropikal
turuncu
ucuz
ulu
unutulmaz
uyduruk
uzak
uzun
verimli
verimsiz
yabani
yapay
yatay
yeni
yitik
yorgun
yuvarlak
zarif
zehirli
zengin
zorlu
),
city: %w(
adana
adıyaman
afyonkarahisar
ağrı
aksaray
amasya
ankara
antalya
ardahan
artvin
aydın
balıkesir
bartın
batman
bayburt
bilecik
bingöl
bitlis
bolu
burdur
bursa
çanakkale
çankırı
çorum
denizli
diyarbakır
düzce
edirne
elazığ
erzincan
erzurum
eskişehir
gaziantep
giresun
gümüşhane
hakkari
hatay
ığdır
ısparta
istanbul
izmir
kahramanmaraş
karabük
karaman
kars
kastamonu
kayseri
kırıkkale
kırklareli
kırşehir
kilis
kocaeli
konya
kütahya
malatya
manisa
mardin
mersin
muğla
muş
nevşehir
niğde
ordu
osmaniye
rize
sakarya
samsun
siirt
sinop
sivas
şanlıurfa
şırnak
tekirdağ
tokat
trabzon
tunceli
uşak
van
yalova
yozgat
zonguldak
),
color: %w(
bej
beyaz
bordo
camgöbeği
gri
kahverengi
kırmızı
lacivert
mavi
mor
pembe
sarı
siyah
turkuvaz
turuncu
yeşil
),
element: %w(
aktinyum
altın
alüminyum
amerikyum
antimon
argon
arsenik
astatin
aynştaynyum
azot
bakır
baryum
berilyum
berkelyum
bizmut
bohriyum
bor
brom
cıva
çinko
darmstadtiyum
demir
disprozyum
dubniyum
erbiyum
evropiyum
fermiyum
flerovyum
flor
fosfor
fransiyum
gadolinyum
galyum
germanyum
gümüş
hafniyum
hassiyum
helyum
hidrojen
holmiyum
indiyum
iridyum
iterbiyum
itriyum
iyot
kadmiyum
kalay
kaliforniyum
kalsiyum
karbon
klor
kobalt
kopernikyum
kripton
krom
ksenon
kurşun
kükürt
küriyum
lantan
lavrensiyum
lityum
livermoryum
lutetyum
magnezyum
mangan
meitneriyum
mendelevyum
molibden
neodimyum
neon
neptünyum
nikel
niobyum
nobelyum
oksijen
osmiyum
paladyum
platin
plütonyum
polonyum
potasyum
praseodim
prometyum
protaktinyum
radon
radyum
renyum
rodyum
röntgenyum
rubidyum
rutenyum
rutherfordiyum
samaryum
seaborgiyum
selenyum
seryum
sezyum
silisyum
skandiyum
sodyum
stronsiyum
talyum
tantal
teknesyum
tellür
terbiyum
titanyum
toryum
tulyum
ununoktiyum
ununpentiyum
ununseptiyum
ununtriyum
uranyum
vanadyum
volfram
zirkonyum
),
fish: %w(
ahtapot
akya
barbunya
hamsi
istavrit
izmarit
kalamar
kalkan
karides
kefal
levrek
mersin
mezgit
midye
morina
orfoz
palamut
ringa
sardalya
sazan
somon
tekir
tirsi
torik
uskumru
vatoz
zargana
),
nato: %w(
alpha
bravo
charlie
delta
echo
foxtrot
golf
hotel
india
juliet
kilo
lima
mike
november
oscar
papa
quebec
romeo
sierra
tango
uniform
victor
whiskey
xray
yankee
zulu
),
noun: %w(
ada
ahtapot
akvaryum
asit
ay
aysberg
bakteri
balon
bayram
beyaz
bisiklet
bomba
bulmaca
buz
cin
cirit
cuma
cumartesi
cumhuriyet
dalgalar
damlalar
dans
dedikodu
deney
deniz
deprem
deve
dikenler
dil
dinozor
dua
duman
efsane
ego
ejderha
embriyo
esinti
fermuar
festival
gece
gergedan
gezegen
girdap
gramofon
gri
hayalet
hayat
hezeyan
hikaye
horoz
hortum
ikilem
iksir
ilkbahar
inek
izler
jeton
jilet
kader
kahve
kalem
kaos
kar
kaya
kedi
kelebek
kent
kertenkele
klarinet
koku
korku
krater
kumsal
kuyu
labirent
lacivert
leblebi
lokomotif
makine
manifesto
mavi
mehtap
melodi
mevsim
meydan
mor
nargile
nehir
nota
nutuk
oda
okyanus
opera
orkide
orman
otlar
ova
oyuncak
papatya
pazar
pazartesi
pembe
piyango
portakal
radar
randevu
rapsodi
robot
saatler
sabah
safari
sayfa
semaver
sinek
siyah
sokak
sonbahar
tayfun
telefon
tepe
tespih
topraklar
tsunami
turuncu
ufuk
uyku
vadi
vapur
volkan
yakamoz
yamyam
yapraklar
yarasa
yaz
yenilgi
yokluk
zafer
zambak
zombi
),
ottoman: %w(
ayn
be
cim
çim
dad
dal
elif
fe
gayn
gef
ha
he
je
kaf
kef
lam
lamelif
mim
nef
nun
ra
sad
se
sin
şın
te
vav
ye
ze
zel
),
phonetic: %w(
adana
bolu
ceyhan
çanakkale
denizli
edirne
fatsa
giresun
hatay
ısparta
izmir
jandarma
kars
lüleburgaz
muş
niğde
ordu
ödemiş
polatlı
rize
sinop
şırnak
tokat
uşak
ünye
van
yozgat
zonguldak
),
roman: %w(
i
ii
iii
iv
v
vi
vii
viii
ix
x
xi
xii
xiii
xiv
xv
xvi
xvii
xviii
xix
xx
xxi
xxii
xxiii
xxiv
xxv
xxvi
xxvii
xxviii
xxix
xxx
xxxi
xxxii
xxxiii
xxxiv
xxxv
xxxvi
xxxvii
xxxviii
xxxix
xl
xli
xlii
xliii
xliv
xlv
xlvi
xlvii
xlviii
xlix
l
li
lii
liii
liv
lv
lvi
lvii
lviii
lix
lx
lxi
lxii
lxiii
lxiv
lxv
lxvi
lxvii
lxviii
lxix
lxx
lxxi
lxxii
lxxiii
lxxiv
lxxv
lxxvi
lxxvii
lxxviii
lxxix
lxxx
lxxxi
lxxxii
lxxxiii
lxxxiv
lxxxv
lxxxvi
lxxxvii
lxxxviii
lxxxix
xc
xci
xcii
xciii
xciv
xcv
xcvi
xcvii
xcviii
xcix
c
)
}
ALPHABET = 'abcçdefghıijklmnoöprsştuüvyz'
CATEGORIES = %i(adjective noun)
SEPARATOR = '-'
def self.alphabet
ALPHABET.chars
end
class MissingCategoriesError < StandardError; end
class WordsMissingError < StandardError; end
class WordsExhaustedError < StandardError; end
attr_reader :categories, :past
def initialize(categories: nil, past: nil, **_)
@categories = categories ? sanitize_categories(categories) : CATEGORIES
@past = past || []
end
def suggest(letters = nil)
letters ||= self.class.alphabet
names, warnings = [], []
letters.each do |letter|
begin
names << generate(letter)
rescue WordsMissingError => detail
warnings << detail.to_s
end
end
[names, warnings]
end
private
def sanitize_categories(given)
result, missings = [], []
given.map(&:to_sym).each do |category|
if DICTIONARY.key? category
result << category
else
missings << category
end
end
return result if missings.empty?
fail MissingCategoriesError, "Varolmayan kategoriler: '#{missings.join(', ')}'." # rubocop:disable Metrics/LineLength
end
def prep_words(words)
words.map { |word| word.downcase.gsub(/\s+/, SEPARATOR) }.sort
end
def alphabetize(dictionary, letter)
result = {}
dictionary.each do |category, words|
result[category] = prep_words(words).select { |word| word[0] == letter }
end
missings = categories.select { |category| result[category].empty? }
unless missings.empty?
fail WordsMissingError, "'#{missings.join(', ')}' kategorilerinde " \
"'#{letter}' ile başlayan kelime yok."
end
result
end
def generate(letter)
dictionary = alphabetize(DICTIONARY, letter)
result = nil
maximum_try(dictionary).times do
result = build(*sample(dictionary))
break unless past.include? result
result = nil
end
return result if result
fail WordsExhaustedError, 'Maksimum deneme sınırına ulaşıldı.'
end
def maximum_try(dictionary)
n = 1
categories.each do |category|
n *= dictionary[category].size
end
n
end
def build(*args)
args.join SEPARATOR
end
def sample(dictionary)
categories.map { |category| dictionary[category].sample }
end
def self.suggest(letters: nil, categories: nil, past: nil, **_)
Generator.new(categories: categories, past: past).suggest(letters)
rescue MissingCategoriesError, WordsExhaustedError => detail
die detail
end
end
class Directory
READMES = %w(
BENIOKU.md benioku.md BENIOKU benioku
README.md readme.md README readme
)
FRONTMATTER = 'abc'
IGNORED = READMES
attr_reader :directory, :past, :letters
def initialize(directory)
@directory = File.expand_path(directory)
@readme = locate
@cache = {}
@setup = setup
end
def categories
@setup[:categories]
end
def letters
Generator.alphabet.reject { |c| used_letters.include? c }
end
def past(extra_directories = [])
directories = @setup[:directories] || []
directories += extra_directories
directories << directory
directories = directories.uniq.select { |d| Dir.exist? d }
result = []
directories.each { |d| result += scan d }
result.uniq.sort
end
private
def setup
sanitize yaml
end
def locate
READMES.map { |f| File.join(directory, f) }.find { |f| File.exist? f }
end
def yaml
result = {}
return result unless (frontmatter = YAML.load_file(@readme)).is_a? Hash
frontmatter.each { |k, v| result[k.to_sym] = v }
result
rescue StandardError => detail
die "#{readme} dosyası yüklenirken hata oluştu.", detail
end
def sanitize(h)
result = {}
result[:directories] = array_from_array_or_string(h[:path]).map do |d|
File.absolute_path(d, directory)
end if h[:path]
result[:categories] = array_from_array_or_string(h[:names])
result
end
def scan(directory, ignored = IGNORED)
return @cache[directory] if @cache.key? directory
result = []
Dir[File.join(directory, '[' + Generator.alphabet.join + ']*')].each do |f|
next unless (name = filter(f, ignored))
result << name
end
@cache[directory] = result.sort
end
def filter(file, ignored)
name = File.basename(file)
return if ignored.include? name
if File.directory? file
name
elsif name =~ /\.*$/
File.basename(name, '.*')
end
end
def used_letters
scan(directory).map { |e| e[0] }.uniq.sort
end
def array_from_array_or_string(value, separator = /\s+/)
case value
when Array, NilClass then value
when String then value.split separator
else fail ArgumentError
end
end
end
module Main
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
def self.option
o = OpenStruct.new(categories: nil, directories: [],
verbose: false, succeeding: false)
OptionParser.new do |option|
option.banner = "Kullanım: #{option.program_name} [seçenekler] [dizin]"
option.separator ''
option.separator 'Seçenekler:'
option.on(
'-cKATEGORİLER', '--categories=KATEGORİLER', ::Array,
'Virgülle ayrılmış kategori listesi'
) do |arg|
o.categories = arg
end
option.on(
'-n', '--next',
'Verilen dizinde kullanılmayan ilk harfle başlayan bir isim üret'
) { o.succeeding = true }
option.on(
'-pDİZİNYOLU', '--path=DİZİNYOLU',
'DİZİNYOLU içindeki dizinlerde üretilen bir ismin varlığını sına'
) do |arg|
arg.split(':').each do |d|
o.directories << File.expand_path(d)
end
end
option.on(
'-v', '--verbose', 'Ayrıntılı bilgi ver'
) { o.verbose = true }
option.on(
'-h', '--help', 'Bu yardımı göster'
) do
$stderr.puts option
exit 2
end
option.parse!
o.categories.map!(&:to_sym) if o.categories
end
o
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
def self.argument(o)
directory = ARGV.shift
if o.succeeding && !directory
die 'Sonraki isim üretimi için dizin verilmeli.'
end
return unless directory
die "Böyle bir dizin yok: '#{directory}" unless Dir.exist? directory
directory
end
def self.setup
o = option
return o unless (d = argument o)
directory = Directory.new d
o.past = directory.past(o.directories)
o.categories ||= directory.categories
o.letters = directory.letters
die "'#{d} dizininde kullanılmayan bir harf bulunamadı." if o.letters.empty?
o
end
def self.report(words, warnings, o)
if words.empty? && !warnings.empty?
die(*warnings, 'Kelime üretilemedi.')
false
elsif !warnings.empty? && o.verbose
cry warnings
true
end
end
def self.main
o = setup
words, warnings = Generator.suggest(o.marshal_dump)
exit 1 if report words, warnings, o
puts o.succeding ? words.first : words.join("\n")
end
end
Main.main
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment