Comments inside a multi-line list in makefile - makefile

I would like to have something like
BROKEN_THINGS = \
thing1 \ # thing1 is completely broken
thing2 \ # thing2 is broken too, see BUG-123
Look like this is not possible with [g]make.
I ended up using warning function (this works because $(warning X) always returns empty string):
BROKEN_THINGS = \
thing1 $(warning "thing1 is completely broken") \
thing2 $(warning "thing2 is broken too, see BUG-123") \
The last is not ideal since warnings garble the output of make (and also warning is a gmake-specific).
Is there a better solution to document a long multi-line list of things?

You can use:
BROKEN_THINGS =
BROKEN_THINGS += thing1 # thing1 is completely broken
BROKEN_THINGS += thing2 # thing2 is broken too, see BUG-123

Related

Can I use strip! and chomp! in one line in Ruby

I see that strip! and chomp! (and other similar methods) return nil when the string is not altered. This apparently forbids combining these methods in one line:
s = 'a' # => "a"
s.strip!.chomp!(',')
# => NoMethodError: undefined method `chomp!' for nil:NilClass
So I seem to be forced to write one per line:
s.strip! # => nil
s.chomp!(',') # => nil
Is this the only way or am I missing something?
You could use the non-mutating versions of those methods:
s = s.strip.chomp(',')
You could use a semicolon (but that would usually be poor taste):
s.strip!; s.chomp!(',')
This looks like a case where tap could be a useful tool:
s.tap {|t| t.strip!}.chomp!
R = /
^\s+ # match >= 1 whitespace at the beginning of string
| # or
,\s*$ # match comma then >= 0 whitespace at the end of the line
| # or
\s+$ # match >= 1 whitespace at the end of the line
/x
def clean(s)
s.gsub!(R,'') || s
end
In all of the following, the return value is "ab", which is also the new value of the string:
clean ' ab '
clean ' ab,'
clean ' ab, '
clean 'ab,'
clean 'ab'

How do I print a Ruby regex variable?

How do I print/display just the part of a regular expression that is between the slashes?
irb> re = /\Ahello\z/
irb> puts "re is /#{re}/"
The result is:
re is /(?-mix:\Ahello\z)/
Whereas I want:
re is /\Ahello\z/
...but not by doing this craziness:
puts "re is /#{re.to_s.gsub( /.*:(.*)\)/, '\1' )}/"
If you want to see the original pattern between the delimiters, use source:
IP_PATTERN = /(?:\d{1,3}\.){3}\d{1,3}/
IP_PATTERN # => /(?:\d{1,3}\.){3}\d{1,3}/
IP_PATTERN.inspect # => "/(?:\\d{1,3}\\.){3}\\d{1,3}/"
IP_PATTERN.to_s # => "(?-mix:(?:\\d{1,3}\\.){3}\\d{1,3})"
Here's what source shows:
IP_PATTERN.source # => "(?:\\d{1,3}\\.){3}\\d{1,3}"
From the documentation:
Returns the original string of the pattern.
/ab+c/ix.source #=> "ab+c"
Note that escape sequences are retained as is.
/\x20\+/.source #=> "\\x20\\+"
NOTE:
It's common to build a complex pattern from small patterns, and it's tempting to use interpolation to insert the simple ones, but that doesn't work as most people think it will. Consider this:
foo = /foo/
bar = /bar/imx
foo_bar = /#{ foo }_#{ bar }/
foo_bar # => /(?-mix:foo)_(?mix:bar)/
Notice that foo_bar has the pattern flags for each of the sub-patterns. Those can REALLY mess you up when trying to match things if you're not aware of their existence. Inside the (?-...) block the pattern can have totally different settings for i, m or x in relation to the outer pattern. Debugging that can make you nuts, worse than trying to debug a complex pattern normally would. How do I know this? I'm a veteran of that particular war.
This is why source is important. It injects the exact pattern, without the flags:
foo_bar = /#{ foo.source}_#{ bar.source}/
foo_bar # => /foo_bar/
Use .inspect instead of .to_s:
> puts "re is #{re.inspect}"
re is /\Ahello\z/

ruby whitespace

are there different sensitivities/settings to whitespace in ruby?
i have a RoR project, where an active record call has a lot of components:
max_stuff = FooSummary.select("max(stuff) as stuff")
.joins(:foo => :bar)
.where("user_id = ? and record_date < ?", r.user_id, r.record_date)
.group("user_id")
.first
1.9.3 works fine with this on my mac, but on the ubuntu server it runs on, it complains about the fact that .joins is on a separate line (unexpected . expecting kEND)
what gives?
This syntax was introduced in Ruby 1.9.1:
Language core changes
New syntax and semantics
…
Newlines allowed before ternary colon operator (:) and method call dot operator (.)
Most likely your server is running an older Ruby version, i.e. 1.9.0 or 1.8.x.
Move the period to the preceding line. If parsing line-by-line,
foo = bar
looks like a full statement, and the next line, taken separately, is a syntax error:
.baz
However, this can't be a statement:
foo = bar.
and the parser knows it has to append the next line as well:
baz
(which gives the same parse as foo = bar.baz, as expected).
Maybe
max_stuff = FooSummary.select("max(stuff) as stuff") \
.joins(:foo => :bar) \
.where("user_id = ? and record_date < ?", r.user_id, r.record_date) \
.group("user_id") \
.first
You can also try various combinations of the following, where either ( ends the line, or ) begins the line. Here I am showing both, and you can adjust to your liking.
max_stuff = FooSummary.select(
"max(stuff) as stuff"
).joins(
:foo => :bar
).where(
"user_id = ? and record_date < ?", r.user_id, r.record_date
).group(
"user_id"
).first
Put dottes on the end of lines
max_stuff = FooSummary.select("max(stuff) as stuff").
joins(:foo => :bar).
where("user_id = ? and record_date < ?", r.user_id, r.record_date).
group("user_id").
first

Specify a nil in command line args

I have a command line tool which generates a flat json doc. Imagine this:
$ ruby gen-json.rb --foo bar --baz qux
{
"foo": "bar"
"baz": "qux"
}
What I want is this to work:
$ ruby gen-json.rb --foo $'\0' --baz qux
{
"foo": null,
"baz": "qux"
}
Instead of null I get an empty string. To simplify the problem even further consider this:
$ cat nil-args.rb
puts "argv[0] is nil" if ARGV[0].nil?
puts "argv[0] is an empty string" if ARGV[0] == ""
puts "argv[1] is nil" if ARGV[1].nil?
I want to run it like this and get this output:
$ ruby nil-args.rb $'\0' foo
argv[0] is nil
But instead I get
argv[0] is an empty string
I suspect this is (arguably) a bug in the ruby interpreter. It is treating argv[0] as a C string which null terminates.
Command line arguments are always strings. You will need to use a sentinel to indicate arguments you want to treat otherwise.
I'm pretty sure you literally cannot do what you are proposing. It's a fundamental limitation of the shell you are using. You can only ever pass string arguments into a script.
It has already been mentioned in a comment but the output you get with the \0 method you tried makes perfect sense. The null terminator technically is an empty string.
Also consider that accessing any element of an array that has not yet been defined will always be nil.
a = [1, 2, 3]
a[10].nil?
#=> true
A possible solution, however, would be for your program to work like this:
$ ruby gen-json.rb --foo --baz qux
{
"foo": null,
"baz": "qux"
}
So when you have a double minus sign argument followed by another double minus sign argument, you infer that the first one was null. You will need to write your own command line option parser to achieve this, though.
Here is a very very simple example script that seems to work (but likely has edge cases and other problems):
require 'pp'
json = {}
ARGV.each_cons(2) do |key, value|
next unless key.start_with? '--'
json[key] = value.start_with?('--') ? nil : value
end
pp json
Would that work for your purposes? :)
Ruby treats EVERYTHING except nil and false as true. Therefore, any empty string will evaluate as true (as well as 0 or 0.0).
You can force the nil behaviour by having something like this:
ARGV.map! do |arg|
if arg.empty?
nil
else
arg
end
end
this way, any empty strings will be transformed in a reference to nil.
You're going to have to decide on a special character to mean nil. I would suggest "\0" (double-quotes ensures the literal string backslash zero is passed in). You can then use a special type converter in OptionParser:
require 'optparse'
require 'json'
values = {}
parser = OptionParser.new do |opts|
opts.on("--foo VAL",:nulldetect) { |val| values[:foo] = val }
opts.on("--bar VAL",:nulldetect) { |val| values[:foo] = val }
opts.accept(:nulldetect) do |string|
if string == '\0'
nil
else
string
end
end
end
parser.parse!
puts values.to_json
Obviously, this requires you to be explicit about the flags you accept, but if you want to accept any flag, you can certainly just hand-jam the if statements for checking for "\0"
As a side note, you can have flags be optional, but you get the empty string passed to the block, e.g.
opts.on("--foo [VAL]") do |val|
# if --foo is passed w/out args, val is empty string
end
So, you'd still need a stand-in

Method chaining on a new line in boo

Is it possible to make method chaining in a new line, like you can do in C#?
var foo = bar
.MethodOne()
.MethodTwo()
whitespace is not significant inside () so the following is legal boo code:
a = (bar
.Foo()
.Bar())
You should use '\' symbol. See sample:
a = 123 \
.ToString() \
.Length
print a

Resources