Neurogami-rhesus 0.2.5 → 0.3.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/README.md +16 -2
- data/Rakefile +107 -1
- data/bin/rhesus +25 -10
- data/lib/rhesus/core.rb +58 -33
- data/lib/rhesus/utils.rb +9 -9
- data/lib/version.rb +1 -5
- data/test/test_rhesus.rb +24 -17
- metadata +2 -3
data/README.md
CHANGED
@@ -24,7 +24,6 @@ The results are copied out to some dir realtive to where you invoked the 'rhesus
|
|
24
24
|
FEATURES/PROBLEMS
|
25
25
|
-----------------
|
26
26
|
|
27
|
-
|
28
27
|
Generates files for you to jump-start projects that have common code.
|
29
28
|
|
30
29
|
Makes asorted assumptions and needs more testing with a variety of template sources
|
@@ -45,11 +44,12 @@ Run `rhesus list` to see the available templates
|
|
45
44
|
|
46
45
|
$ rhesus list
|
47
46
|
|
47
|
+
NOTE: This behavior might vanish, since in actual use it is actually useless. See below.
|
48
|
+
|
48
49
|
|
49
50
|
Run `rhesus gen` to generate code from a template. You may optionally pass the name
|
50
51
|
of a template, but if you leave that out you'll get a list to pick from.
|
51
52
|
|
52
|
-
|
53
53
|
$ rhesus gen
|
54
54
|
1: jimpanzee.about
|
55
55
|
2: jimpanzee.basic
|
@@ -57,6 +57,16 @@ of a template, but if you leave that out you'll get a list to pick from.
|
|
57
57
|
|
58
58
|
Enter the number of the template to use:
|
59
59
|
|
60
|
+
If you pass a complete template name then that is automatically used:
|
61
|
+
|
62
|
+
$ rhesus gen jimpanzee.midi
|
63
|
+
|
64
|
+
Run `rhesus stuff` to have rhesus show a list of templates that match on `stuff`.
|
65
|
+
|
66
|
+
$ rhesus midi
|
67
|
+
1: jimpanzee.midi
|
68
|
+
|
69
|
+
Enter the number of the template to use:
|
60
70
|
|
61
71
|
|
62
72
|
The code assumes you have a directory `.rhesus` in your home directory (+~/.rhesus+)
|
@@ -194,6 +204,10 @@ A value of `FooBar`, for example, would create `src/foo_bar/foo_bar.rb`. But th
|
|
194
204
|
|
195
205
|
|
196
206
|
|
207
|
+
Note: Some of the code for auto-mangling file and path names is changing. Initially the code was specific to Ruby apps, but it's really very handy for all sorts of things, such as Haskell projects.
|
208
|
+
|
209
|
+
But these other things have different conventions; code to apply appropriate conventions is being added.
|
210
|
+
|
197
211
|
|
198
212
|
REQUIREMENTS
|
199
213
|
-------------
|
data/Rakefile
CHANGED
@@ -26,7 +26,6 @@ PROJ.version = Neurogami::Rhesus::VERSION
|
|
26
26
|
PROJ.readme_file = 'README.md'
|
27
27
|
PROJ.summary = "Really simple, practical code generator."
|
28
28
|
|
29
|
-
# PROJ.spec.opts << '--color'
|
30
29
|
|
31
30
|
desc "Bacon specs"
|
32
31
|
task 'test:bacon' do
|
@@ -36,4 +35,111 @@ end
|
|
36
35
|
|
37
36
|
desc 'test'
|
38
37
|
task :test => 'test:bacon'
|
38
|
+
|
39
|
+
namespace :issues do
|
40
|
+
desc 'Open issues'
|
41
|
+
task :open do
|
42
|
+
paged_issues ENV['GH_NO_CACHE']
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Create a new issue'
|
46
|
+
task :create do
|
47
|
+
issue_details = ENV['DETAILS'].to_s.strip
|
48
|
+
if issue_details.empty?
|
49
|
+
warn "No issue details!"
|
50
|
+
else
|
51
|
+
title, body = issue_details.split(' -- ', 2)
|
52
|
+
create_issue title, body
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
def create_issue title, body
|
59
|
+
require 'net/http'
|
60
|
+
require 'uri'
|
61
|
+
|
62
|
+
|
63
|
+
token = ENV['GH_AUTH_TOKEN']
|
64
|
+
url = 'http://github.com/api/v2/yaml/issues/open/Neurogami/rhesus'
|
65
|
+
res = Net::HTTP.post_form(URI.parse(url),
|
66
|
+
{'title'=> title,
|
67
|
+
'body' => body,
|
68
|
+
'login' => 'Neurogami',
|
69
|
+
'token'=> token }
|
70
|
+
)
|
71
|
+
warn res.body
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
def ___
|
76
|
+
warn "\n" + '_' * 30
|
77
|
+
end
|
78
|
+
|
79
|
+
def paged_issues no_cache = false
|
80
|
+
ARGV.clear
|
81
|
+
warn "Hit enter after each issue to see the next one"
|
82
|
+
issues(no_cache).each do |issue|
|
83
|
+
___
|
84
|
+
warn "Title: #{issue['title']}"
|
85
|
+
warn "Details: \n#{issue['body']}"
|
86
|
+
___
|
87
|
+
gets
|
88
|
+
end
|
89
|
+
warn "\nThat's it!"
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
def issues no_cache = false
|
94
|
+
issues_cache = 'issues.yaml'
|
95
|
+
if no_cache || !File.exist?(issues_cache)
|
96
|
+
warn "Reloading issues from GitHub ..."
|
97
|
+
File.open( issues_cache, 'w'){ |f| f.puts get_issues }
|
98
|
+
end
|
99
|
+
YAML.load(IO.read(issues_cache))['issues']
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_issues
|
103
|
+
#require 'yaml'
|
104
|
+
# url = 'http://github.com/api/v2/yaml/issues/list/Neurogami/rhesus/open'
|
105
|
+
# open(url).read
|
106
|
+
|
107
|
+
%~---
|
108
|
+
issues:
|
109
|
+
- user: Neurogami
|
110
|
+
updated_at: 2009-08-25 11:15:11 -07:00
|
111
|
+
body: "The app started out to handle Ruby code, but is handy for almost anything (such as layout out a Haskel project). But not all languages use the same CamelCase and snake_case conventions. \r\n\
|
112
|
+
\r\n\
|
113
|
+
When the code is inventing file names it needs to follow appropriate language conventions. "
|
114
|
+
title: All variable-driven file names are snake_cased by default
|
115
|
+
number: 1
|
116
|
+
votes: 0
|
117
|
+
closed_at:
|
118
|
+
labels:
|
119
|
+
- configuration
|
120
|
+
created_at: 2009-08-25 10:09:44 -07:00
|
121
|
+
state: open
|
122
|
+
- user: Neurogami
|
123
|
+
updated_at: 2009-08-25 10:16:28 -07:00
|
124
|
+
body: |-
|
125
|
+
Running
|
126
|
+
|
127
|
+
rhesus list
|
128
|
+
|
129
|
+
or
|
130
|
+
|
131
|
+
rhesus gen
|
132
|
+
|
133
|
+
gives a full list of available templates, which can get too big to be useful.
|
134
|
+
title: CLI UI won't scale
|
135
|
+
number: 2
|
136
|
+
votes: 0
|
137
|
+
closed_at:
|
138
|
+
labels:
|
139
|
+
- UI
|
140
|
+
created_at: 2009-08-25 10:13:53 -07:00
|
141
|
+
state: open
|
142
|
+
~
|
143
|
+
end
|
144
|
+
|
39
145
|
# EOF
|
data/bin/rhesus
CHANGED
@@ -26,7 +26,7 @@ def help(message = nil)
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def process_template template_name
|
29
|
-
puts "Using template #{template_name}"
|
29
|
+
puts " - Using template #{template_name.inspect}"
|
30
30
|
|
31
31
|
var_set = {}
|
32
32
|
|
@@ -92,20 +92,33 @@ def copy_over_default_templates
|
|
92
92
|
FileUtils.cp_r File.dirname(__FILE__) + "/../default-templates/.", Neurogami::Rhesus::Core.user_template_directory
|
93
93
|
end
|
94
94
|
|
95
|
-
def generate_from_template
|
95
|
+
def generate_from_template filter = /.*/
|
96
|
+
|
97
|
+
filter = Regexp.new(filter) unless filter.is_a?(Regexp)
|
98
|
+
|
96
99
|
if ARGV.first
|
97
|
-
|
100
|
+
ARGV.first.strip!
|
101
|
+
t = Neurogami::Rhesus::Core.templates.find{ |t| t == ARGV.first }
|
102
|
+
ARGV.clear
|
103
|
+
process_template t
|
98
104
|
else
|
99
|
-
|
105
|
+
templates = {}
|
106
|
+
Neurogami::Rhesus::Core.templates.select{ |t| t =~ filter }.each_with_index do |template, idx|
|
107
|
+
templates[idx+1] = template
|
100
108
|
puts "#{idx+1}: #{template}"
|
101
109
|
end
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
item =
|
110
|
+
if templates.empty?
|
111
|
+
warn "No templates matched on #{filter.pretty_inspect.strip}."
|
112
|
+
else
|
113
|
+
item = 0
|
114
|
+
while item < 1 || item-1 > Neurogami::Rhesus::Core.templates.size
|
115
|
+
print "Enter the number of the template to use: "
|
116
|
+
item = gets.to_i
|
117
|
+
end
|
118
|
+
|
119
|
+
process_template templates[item] # Neurogami::Rhesus::Core.templates[item-1]
|
106
120
|
end
|
107
121
|
|
108
|
-
process_template Neurogami::Rhesus::Core.templates[item-1]
|
109
122
|
end
|
110
123
|
end
|
111
124
|
#-------------------------------------------------
|
@@ -127,7 +140,9 @@ else
|
|
127
140
|
when '--setup'
|
128
141
|
setup
|
129
142
|
else
|
130
|
-
puts "Nothing known about #{ARGV[0]}"
|
143
|
+
#puts "Nothing known about #{ARGV[0]}"
|
144
|
+
# Treat the same as gen, but use the argument as a pattern filter to reduce the number of items show
|
145
|
+
generate_from_template option.strip
|
131
146
|
end
|
132
147
|
end
|
133
148
|
|
data/lib/rhesus/core.rb
CHANGED
@@ -19,10 +19,6 @@ module Neurogami
|
|
19
19
|
module Rhesus
|
20
20
|
|
21
21
|
class Core
|
22
|
-
# Hacky :( FIXME Add a better way to define what files get slurped for parsing
|
23
|
-
haz_vars = %w{ rb txt rhtml ini yml yaml Rakefile rake gemspec feature}
|
24
|
-
@@re = haz_vars.map { |x| x + '$' }.join( '|')
|
25
|
-
@@re = Regexp.new "(#{@@re})$"
|
26
22
|
|
27
23
|
# http://refactormycode.com/codes/281-given-a-hash-of-variables-render-an-erb-template
|
28
24
|
@@m = Module.new do
|
@@ -45,40 +41,40 @@ module Neurogami
|
|
45
41
|
end
|
46
42
|
end
|
47
43
|
|
48
|
-
def self.process_template
|
44
|
+
def self.process_template template_text, variables_hash
|
49
45
|
create_methods_from_hash variables_hash
|
50
|
-
t = ERB.new(
|
46
|
+
t = ERB.new(template_text, 0, "%<>")
|
51
47
|
t.result @@m.binding
|
52
48
|
end
|
53
49
|
|
54
50
|
def self.projects
|
55
51
|
get_projects_directories.map { |path|
|
56
52
|
path.sub! user_template_directory + '/', ''
|
57
|
-
#path.identifier_to_path!
|
58
53
|
path
|
59
54
|
}
|
60
55
|
end
|
61
56
|
|
62
|
-
|
63
|
-
|
64
57
|
def self.tuple_base_name_pair name
|
65
58
|
[snake_case(name), camelize(name)]
|
66
59
|
end
|
67
60
|
|
68
61
|
|
62
|
+
#
|
69
63
|
def self.required_vars_for_template_set template_name
|
70
64
|
#template_name.identifier_to_path!
|
71
|
-
vars =
|
65
|
+
vars = []
|
72
66
|
|
73
67
|
selected_template_files(template_name).map do |path|
|
74
68
|
next unless File.file? path
|
75
69
|
next unless path =~ @@re
|
76
|
-
|
77
|
-
required_vars(
|
78
|
-
|
79
|
-
|
70
|
+
file_lines = IO.readlines path
|
71
|
+
vars.concat(required_vars(file_lines))
|
72
|
+
#file_lines.each do |v|
|
73
|
+
# vars[v] = v
|
74
|
+
#end
|
80
75
|
end
|
81
|
-
vars.
|
76
|
+
vars.uniq!
|
77
|
+
vars.sort
|
82
78
|
end
|
83
79
|
|
84
80
|
def self.templates
|
@@ -89,18 +85,15 @@ module Neurogami
|
|
89
85
|
end
|
90
86
|
end
|
91
87
|
|
92
|
-
def self.required_vars
|
93
|
-
vars =
|
94
|
-
|
95
|
-
l
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
varname = varname.split('.').first
|
100
|
-
vars[varname] = varname
|
101
|
-
end
|
88
|
+
def self.required_vars file_lines
|
89
|
+
vars = []
|
90
|
+
file_lines.each do |l|
|
91
|
+
vars.concat l.scan(/(<%=)\s*(\S+)\s*(%>)/).map{ |m| m[1].strip.split('.').first}
|
92
|
+
#variables.each do |v|
|
93
|
+
# vars[v] = v
|
94
|
+
#end
|
102
95
|
end
|
103
|
-
vars.
|
96
|
+
vars.uniq
|
104
97
|
end
|
105
98
|
|
106
99
|
|
@@ -116,13 +109,12 @@ module Neurogami
|
|
116
109
|
end
|
117
110
|
|
118
111
|
def self.selected_template_files template_name
|
119
|
-
|
120
|
-
Dir.glob user_template_directory + '/' + template_name + '/**/*'
|
112
|
+
Dir.glob( user_template_directory + '/' + template_name + '/**/*', File::FNM_DOTMATCH).select { |f| f !~ /\.$/ }
|
121
113
|
end
|
122
114
|
|
123
|
-
def self.add_user_haz_vars
|
124
|
-
if File.exist?(File.expand_path( '
|
125
|
-
IO.readlines(File.expand_path( '
|
115
|
+
def self.add_user_haz_vars haz_vars
|
116
|
+
if File.exist?(File.expand_path( user_template_directory + '/haz_vars.txt'))
|
117
|
+
IO.readlines(File.expand_path( user_template_directory + '/haz_vars.txt')).each { |x| haz_vars << x.strip unless x.strip.empty? }
|
126
118
|
end
|
127
119
|
end
|
128
120
|
|
@@ -134,11 +126,36 @@ module Neurogami
|
|
134
126
|
File.expand_path "~/.rhesus"
|
135
127
|
end
|
136
128
|
|
129
|
+
def self.language_appropriate_renaming path, template_var, given_value
|
130
|
+
# Hack to see what might work:
|
131
|
+
renaming_map = {
|
132
|
+
/\.rb$/ => :to_snake_case
|
133
|
+
}
|
134
|
+
renaming_map.each do |file_pattern, renaming_method|
|
135
|
+
if path =~ file_pattern
|
136
|
+
return path.gsub( template_var, given_value.send(renaming_method) )
|
137
|
+
end
|
138
|
+
end
|
139
|
+
path.gsub( template_var, given_value )
|
140
|
+
end
|
141
|
+
|
142
|
+
# How can this be tested? This method is more or less the core of the
|
143
|
+
# tool (other key method: extracting the set of vars from the templates)
|
144
|
+
# The trouble is that the code works by creating a side effect; the return
|
145
|
+
# value is nothing.
|
146
|
+
#
|
147
|
+
# This method does multiple things: computes file paths;
|
148
|
+
# alters file path basedon variable values; calls
|
149
|
+
# out to read in file text, alter it with variable subsition, and
|
150
|
+
# write it out; do direct file copies.
|
151
|
+
|
137
152
|
def self.process template_name, var_set, location, path
|
138
153
|
relative_path = path.sub user_template_directory , ''
|
139
154
|
short_path = path.sub user_template_directory, ''
|
140
155
|
real_path = short_path.sub(template_name + '/', '')
|
141
|
-
|
156
|
+
|
157
|
+
var_set.each { |key, value| real_path = language_appropriate_renaming( real_path, key, value ) }
|
158
|
+
|
142
159
|
write_to = location + real_path
|
143
160
|
destination_dir = File.expand_path(File.dirname(write_to))
|
144
161
|
FileUtils.mkdir_p destination_dir
|
@@ -146,7 +163,8 @@ module Neurogami
|
|
146
163
|
rename( file_to_write_to ) if File.exist? file_to_write_to
|
147
164
|
# Do a straight file copy unless this file might be using Erb
|
148
165
|
if path =~ @@re
|
149
|
-
|
166
|
+
source_text = IO.read path
|
167
|
+
text = process_template source_text, var_set
|
150
168
|
File.open(file_to_write_to, "w"){|f| f.puts text }
|
151
169
|
else
|
152
170
|
FileUtils.cp path, file_to_write_to
|
@@ -159,6 +177,13 @@ module Neurogami
|
|
159
177
|
FileUtils.mv full_file_path, full_file_path + '.' + ts
|
160
178
|
end
|
161
179
|
|
180
|
+
|
181
|
+
# Hacky :( FIXME Add a better way to define what files get slurped for parsing
|
182
|
+
haz_vars = %w{ rb txt rhtml ini yml yaml Rakefile rake gemspec feature}
|
183
|
+
add_user_haz_vars haz_vars
|
184
|
+
@@re = haz_vars.map { |x| x + '$' }.join( '|')
|
185
|
+
@@re = Regexp.new "(#{@@re})$"
|
186
|
+
|
162
187
|
end
|
163
188
|
end
|
164
189
|
end
|
data/lib/rhesus/utils.rb
CHANGED
@@ -9,15 +9,15 @@ def template_base_dir
|
|
9
9
|
File.expand_path( File.join( File.dirname(__FILE__), '..', 'templates' ) )
|
10
10
|
end
|
11
11
|
|
12
|
-
def copy_over_prebuilt_template base_path, name
|
13
|
-
%w{model view controller ui}.each do |unit|
|
14
|
-
FileUtils.mkdir_p File.join(base_path, name)
|
15
|
-
from = File.join( template_base_dir, name , name + '_' + unit + '.rb')
|
16
|
-
dest = File.join(base_path, name, name + '_' + unit + '.rb' )
|
17
|
-
warn "cp '#{from}' to '#{dest}'"
|
18
|
-
FileUtils.cp from, dest
|
19
|
-
end
|
20
|
-
end
|
12
|
+
#def copy_over_prebuilt_template base_path, name
|
13
|
+
# %w{model view controller ui}.each do |unit|
|
14
|
+
# FileUtils.mkdir_p File.join(base_path, name)
|
15
|
+
# from = File.join( template_base_dir, name , name + '_' + unit + '.rb')
|
16
|
+
# dest = File.join(base_path, name, name + '_' + unit + '.rb' )
|
17
|
+
# warn "cp '#{from}' to '#{dest}'"
|
18
|
+
# FileUtils.cp from, dest
|
19
|
+
# end
|
20
|
+
#end
|
21
21
|
|
22
22
|
def setup_directory path
|
23
23
|
FileUtils.mkdir_p path.gsub("\\", "/")
|
data/lib/version.rb
CHANGED
data/test/test_rhesus.rb
CHANGED
@@ -2,22 +2,24 @@ require 'rubygems'
|
|
2
2
|
require 'bacon'
|
3
3
|
require 'lib/rhesus/core'
|
4
4
|
|
5
|
+
$here = File.expand_path(File.dirname(__FILE__))
|
6
|
+
|
5
7
|
describe 'A rhesus directory' do
|
6
8
|
|
7
9
|
before do
|
10
|
+
|
8
11
|
@nrc = Neurogami::Rhesus::Core
|
9
12
|
class Neurogami::Rhesus::Core
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
def self.user_template_directory
|
14
|
+
"#{$here}/.rhesus"
|
15
|
+
end
|
14
16
|
end
|
15
17
|
|
16
18
|
end
|
17
19
|
|
18
|
-
|
20
|
+
# Not all that useful ....
|
19
21
|
it 'should be in the home directory' do
|
20
|
-
@nrc.user_template_directory.should.equal '
|
22
|
+
@nrc.user_template_directory.should.equal $here + '/.rhesus'
|
21
23
|
end
|
22
24
|
|
23
25
|
it 'should exist' do
|
@@ -32,20 +34,25 @@ describe 'A rhesus directory' do
|
|
32
34
|
@nrc.templates.size.should.equal 5
|
33
35
|
end
|
34
36
|
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'The core Rhesus code' do
|
35
40
|
|
36
|
-
|
37
|
-
|
41
|
+
it 'really needs to populate an Erb string with key/value pairs' do
|
42
|
+
template_text = "I've got <%= adj1 %>, \nand I'm <%= adj2 %> <%= adj3 %>"
|
43
|
+
variable_set = { :adj1 => 'soul' , :adj2 => 'super', :adj3 => 'bad' }
|
44
|
+
new_text = Neurogami::Rhesus::Core.process_template template_text, variable_set
|
45
|
+
new_text.should == "I've got soul, \nand I'm super bad"
|
46
|
+
end
|
38
47
|
|
39
|
-
|
40
|
-
|
41
|
-
# pt.class.should.equal Neurogami::Rhesus::TemplateSet
|
42
|
-
#end
|
48
|
+
it 'dang well better extract variable names from Erb, bro' do
|
49
|
+
template_text = "I've got <%= adj1 %>, \nand I'm <%= adj2 %> <%= adj3 %>. And I mean <%= adj2 %> <%= adj3 %>"
|
43
50
|
|
44
|
-
|
51
|
+
vars = Neurogami::Rhesus::Core.required_vars template_text.split( "\n")
|
52
|
+
vars.sort!
|
53
|
+
vars.should == ['adj1', 'adj2', 'adj3' ]
|
45
54
|
|
46
|
-
|
55
|
+
end
|
47
56
|
|
48
|
-
|
57
|
+
end
|
49
58
|
|
50
|
-
* List available templates
|
51
|
-
* Use one of those templates
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: Neurogami-rhesus
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Britt / Neurogami
|
@@ -56,7 +56,6 @@ files:
|
|
56
56
|
- test/test_rhesus.rb
|
57
57
|
has_rdoc: false
|
58
58
|
homepage: http://www.neurogami.com/code
|
59
|
-
licenses:
|
60
59
|
post_install_message:
|
61
60
|
rdoc_options:
|
62
61
|
- --main
|
@@ -80,7 +79,7 @@ requirements: []
|
|
80
79
|
rubyforge_project: !binary |
|
81
80
|
AA==
|
82
81
|
|
83
|
-
rubygems_version: 1.
|
82
|
+
rubygems_version: 1.2.0
|
84
83
|
signing_key:
|
85
84
|
specification_version: 3
|
86
85
|
summary: Really simple, practical code generator.
|