PlantUML: With preprocessor, how to check if key is present? - plantuml
With a dictionary variable, I would like to check the presence of a key
!$domain_color?={
"technical": "#gray"
}
frame input $INPUT_COLOR {
!if "technical" in $domain_color
ABC -> bad
!else
def -> ok
!endif
How I can do that?
I think it's enough to check the value (!if $domain_color.technical):
#startuml
!$domain_color?={ "technical": "#gray" }
'!$domain_color?={ "fred": "#gray" }
frame input $INPUT_COLOR {
!if $domain_color.technical
ABC -> bad
!else
def -> ok
!endif
#enduml
If you uncomment the line defining fred and comment the line defining technical you can see that your diagram changes.
Related
ref to a hash -> its member array -> this array's member's value. How to elegantly access and test?
I want to use an expression like #{ %$hashref{'key_name'}[1] or %$hashref{'key_name}->[1] to get - and then test - the second (index = 1) member of an array (reference) held by my hash as its "key_name" 's value. But, I can not. This code here is correct (it works), but I would have liked to combine the two lines that I have marked into one single, efficient, perl-elegant line. foreach my $tag ('doit', 'source', 'dest' ) { my $exists = exists( $$thisSectionConfig{$tag}); my #tempA = %$thisSectionConfig{$tag} ; #this line my $non0len = (#tempA[1] =~ /\w+/ ); # and this line if ( !$exists || !$non0len) { print STDERR "No complete \"$tag\" ... etc ... \n"; # program exit ... } I know you (the general 'you') can elegantly combine these two lines. Could someone tell me how I could do this? This code it testing a section of a config file that has been read into a $thisSectionConfig reference-to-a-hash by Config::Simple. Each config file key=value pair then is (I looked with datadumper) held as a two-member array: [0] is the key, [1] is the value. The $tag 's are configuration settings that must be present in the config file sections being processed by this code snippet. Thank you for any help.
You should read about Arrow operator(->). I guess you want something like this: foreach my $tag ('doit', 'source', 'dest') { if(exists $thisSectionConfig -> {$tag}){ my $non0len = ($thisSectionConfig -> {$tag} -> [1] =~ /(\w+)/) ; } else { print STDERR "No complete \"$tag\" ... etc ... \n"; # program exit ... }
NoneType Buffer interface error in windows 8
I am making a text editor, so you can imagine that there is a lot of manipulating text files. When I double click on the .py file to run it in python.exe in windows, it throws an error of 'NoneType does not support the Buffer interface' As I have only ever heard "buffer" as a programming term in the context of text files, I believe the problem is somewhere in there. Here is the code: from tkinter import * from tkinter.filedialog import * from tkinter.messagebox import * import os os.chdir(os.getenv('HOME')) current=None backup='' def newfile(): def create_file(entry): global current global root nonlocal create_in nonlocal name_it current = open(entry.get(),'w') root.title(create_in+'/'+current.name+' - Aspus') name_it.destroy() create_in=askdirectory() if create_in!='': global root os.chdir(create_in) name_it=Tk() name_it.title("Name the File?") prompt=Label(name_it, text="Enter name for new file:") prompt.grid(row=0) entry=Entry(name_it) entry.grid(row=1) entry.insert(0, "Untitled.txt") create=Button(name_it, text="Create", command = lambda: create_file(entry)) create.grid(row=1, column=3) name_it.mainloop() def openfile(master): global current global backup opening=askopenfilename() file=open(opening, 'r') insert=file.read() backup=file.read() file.close() file=open(opening, 'w') current=file master.title(current.name+' - Aspus') return insert def savefile(entry): global current if current!=None: current.write(entry.get('1.0', END)) elif current==None: newfile() current.write(entry.get('1.0', END)) def ask_save(): global root global current global main if current!=None: save_exit=askyesnocancel("Save Before Exit?", "Do you want to save before exiting?") if save_exit==True: a=current.name current.close() current=open(a, 'w') savefile(main) current.close() root.destroy() exit() elif save_exit==False: a=current.name current.close() current=open(a, 'w') current.write(backup) current.close() root.destroy() exit() elif current==None: if main.get('0.1', END).strip()!='': save_exit=askyesnocancel("Save Before Exit?", "Do you want to save before exiting?") if save_exit==True: newfile() savefile() current.close() root.destroy() elif save_exit==False: root.destroy() else: root.destroy() def setpgwidth(): def adjust(entry): global main new_width=entry.get() try: main.config(width=int(entry.get())) except: showerror("Invalid width", "You entered an invalid width. Expected an integer.") entry.delete(0, END) else: main.pack(expand=Y, fill=Y, side=LEFT) entry.master.destroy() width=Tk() width.title("Set Page Width") prompt=Label(width, text="Enter new page width:") prompt.grid(row=0, column=0, columnspan=2) new=Entry(width) new.grid(row=1, column=0) submit=Button(width, text="Submit", command=lambda: adjust(new)) submit.grid(row=1, column=1) width.mainloop() root=Tk() root.title("Aspus Text Editor") #create main text widget main=Text(root, wrap=WORD) main.pack(expand=True, fill=BOTH, side=LEFT) #create scrollbar scroll=Scrollbar(root) scroll.pack(side=RIGHT, fill=Y) #configure scrollbar scroll.config(command=main.yview) main.config(yscrollcommand=scroll.set) #Creating menus menu=Menu(root) root.config(menu=menu) menu.add_command(label="New File", command=newfile) menu.add_command(label="Open File", command=lambda: main.insert(END, openfile(root))) menu.add_command(label="Save File", command=lambda: savefile(main)) formatmenu=Menu(menu) menu.add_cascade(label="Format", menu=formatmenu) formatmenu.add_command(label="Set Page Width", command=setpgwidth) menu.add_command(label="Quit", command=ask_save) root.protocol("WM_DELETE_WINDOW", ask_save) root.mainloop() Does anyone know why this is happening and how to avoid it?
At least part of the problem is these two statements: insert=file.read() backup=file.read() Because read() reads the whole file, backup isn't going to be what you think it is. The first thing to do is step through the code with pdb, or add some print statements to validate that your data is what you think it is. You're relying heavily on global variables which can easily be changed in an order different than what you expect.
Recursing directories only goes one file deep
I have the following code: find_info(File) -> case file:read_file_info(File) of {ok, Facts} -> case Facts#file_info.type of directory -> directory; regular -> regular end; {error,Reason} -> exit(Reason) end. find_files(Dir,Flag,Ending,Acc) -> case file:list_dir(Dir) of {ok,A} -> find_files_helper(A,Dir,Flag,Acc,Ending); {_,_} -> Acc end. find_files_helper([H|Tail],Dir,Flag,Acc,Ending) -> A = find_info(filename:absname_join(Dir,H)), case A of directory -> case Flag of true -> find_files(filename:absname_join(Dir,H),Flag,Ending,Acc ++ find_files_helper(Tail,Dir,Flag,Acc,Ending)); false -> find_files_helper(Tail,Dir,Flag,Acc,Ending) end; regular -> case filename:extension(H) of Ending -> find_files_helper(Tail,Dir,Flag,[to_md5_large(H)] ++ Acc, Ending); _ -> find_files_helper(Tail,Dir,Flag,Acc,Ending) end; {error,Reason} -> exit(Reason) end; find_files_helper([],_,_,Acc,_) -> Acc. However whenever I run the find_files/4 the program only goes one file deep before crashing. Say I have the following directory home/ a/ ser.erl b/ c/ file.erl file2.erl When run I will get the md5 of file.erl of file2.erl and of ser.erl. However if the directory looks like this: home/ a/ ser.erl back.erl b/ c/ file.erl file2.erl Then the whole program crashes. I have spent few good hours looking for what I'm missing here in my logic however I have no idea. The error message that I get is exception enoent in function p:to_md5_large/1. In case the md5 is needed here it is: to_md5_large(File) -> case file:read_file(File) of {ok, <<B/binary>>} -> md5_helper(B,erlang:md5_init()); {error,Reason} -> exit(Reason) end. md5_helper(<<A:4/binary,B>>,Acc) -> md5_helper(B,erlang:md5_update(Acc,A)); md5_helper(A,Acc) -> B = erlang:md5_update(Acc,A), erlang:md5_final(B).
You're getting enoent because you're passing a filename like back.erl to to_md5_large when you're not in the directory where back.erl is located. Try passing the full filename instead. You're already calling filename:absname_join(Dir,H) in find_files_helper, so just save that to a variable and pass that variable instead of H to to_md5_large.
There is a function that does this for you: fold_files(Dir, RegExp, Recursive, Fun, AccIn) -> AccOut in your case: Result = filelib:fold_files(Dir, ".*\.erl", true, fun(X,Acc) -> {ok,B} = file:read_file(X), [erlang:md5(B)|Acc] end, []). [edit] #Bula: I didn't answer directly to your question for 2 reasons: The first one is that, at the time I was writing my answer, you didn't provide the type of error you get. It is very important, with any language, to learn how to get information from error report. In erlang, most of the time, you get the error type an the line where it occurs, looking at the documentation you will have a very helpful information about what was going wrong. By the way, unless you want to manage errors, I discourage you to write things like: case file:read_file(File) of {ok, <<B/binary>>} -> md5_helper(B,erlang:md5_init()); {error,Reason} -> exit(Reason) end. The following code will do the same, shorter, and you'll get the exact line number where you got an issue (its not the best example in your code, but it's the shorter) {ok, <<B/binary>>} = file:read_file(File), md5_helper(B,erlang:md5_init()), The second is that I find your code too big, with useless helper functions. I think it is important to try to have a concise and readable code, and also to try to use the library function in the right way. For example you are using erlang:md5:init/0, erlang:md5_update/2 and erlang:md5_final/1 while a single call to erlang:md5/1 is enough in your case. The way you use it exists to be able to calculate the md5 when you get the data chunk by chunk, which is not your case, and the way you wrote the helper function does not allow to use this feature. I don't understand why you want to have a "deployed" version of your code, but I propose you another version where I tried to follow my advices (written directly in the shell, so it need R17+ for the definition of recursive anonymous function) :o) 1> F = fun F(X,D,Ending) -> 1> {ok,StartD} = file:get_cwd(), %% save current directory 1> ok = file:set_cwd(D), %% move to the directory to explore 1> R = case filelib:is_dir(X) of 1> true -> %% if the element to analyze is a directory 1> {ok,Files} = file:list_dir(X), %% getits content 1> [F(Y,X,Ending) || Y <- Files]; %% and recursively analyze all its elements 1> false -> 1> case filelib:is_regular(X) andalso (filename:extension(X) == Ending) of 1> true -> %% if it is a regular file with the right extension 1> {ok,B} = file:read_file(X), %% read it 1> [erlang:md5(B)]; %% and calculate the md5 (must be return in a list 1> %% for consistancy with directory results) 1> false -> 1> [] %% in other cases (symlink, ...) return empty 1> end 1> end, 1> ok = file:set_cwd(StartD), %% restore current directory 1> lists:flatten(R) %% flatten for nicer result 1> end. #Fun<erl_eval.42.90072148> 2> Md5 = fun(D) -> F(D,D,".erl") end. #Fun<erl_eval.6.90072148> 3> Md5("C:/My programs/erl6.2/lib/stdlib-2.2"). [<<150,238,21,49,189,164,184,32,42,239,200,52,135,78,12, 112>>, <<226,53,12,102,125,107,137,149,116,47,50,30,37,13,211,243>>, <<193,114,120,24,175,27,23,218,7,169,146,8,19,208,73,255>>, <<227,219,237,12,103,218,175,238,194,103,52,180,132,113, 184,68>>, <<6,16,213,41,39,138,161,36,184,86,17,183,125,233,20,125>>, <<23,208,91,76,69,173,159,200,44,72,9,9,50,40,226,27>>, <<92,8,168,124,230,1,167,199,6,150,239,62,146,119,83,36>>, <<100,238,68,145,58,22,88,221,179,204,19,26,50,172,142,193>>, <<253,79,101,49,78,235,151,104,188,223,55,228,163,25,16, 147>>, <<243,189,25,98,170,97,88,90,174,178,162,19,249,141,94,60>>, <<237,85,6,153,218,60,23,104,162,112,65,69,148,90,15,240>>, <<225,48,238,193,120,43,124,63,156,207,11,4,254,96,250,204>>, <<67,254,107,82,106,87,36,119,140,78,216,142,66,225,8,40>>, <<185,246,227,162,211,133,212,10,174,21,204,75,128,125, 200,...>>, <<234,191,210,59,62,148,130,187,60,0,187,124,150,213,...>>, <<199,231,45,34,185,9,231,162,187,130,134,246,54,...>>, <<157,226,127,87,191,151,81,50,19,116,96,121,...>>, <<15,59,143,114,184,207,96,164,155,44,238,...>>, <<176,139,190,30,114,248,0,144,201,14,...>>, <<169,79,218,157,20,10,20,146,12,...>>, <<131,25,76,110,14,183,5,103,...>>, <<91,197,189,2,48,142,67,...>>, <<94,202,72,164,129,237,...>>, <<"^NQÙ¡8hÿèkàå"...>>,<<"ðÙ.Q"...>>, <<150,101,76,...>>, <<"A^ÏrÔ"...>>,<<"¹"...>>,<<...>>|...] 4>
How do I check for pangrams in a line in ruby?
Some of you may notice I'm already back with the same painful code already. I'm not sure if the other question is still open or not once I accept an answer. Now the problem is a little simpler. I found some code that checked for pangrams. It use to be def pangram?('sentence') but I needed line to go in there so I tried changing it to def pangram?(line). It doesn't seem to mesh well with my coding style and doesn't work. I tried to use .contain('a' . . 'z') to check for a pangram but someone I know tried that and it didn't work. Also google isn't much help either. Any ideas for how I could check for pangrams in an if stmt? # To change this template, choose Tools | Templates # and open the template in the editor # This program reads a file line by line, #separating lines by writing into certain text files. #PPQ - Pangrams, Palindromes, and Quotes class PPQ def pangram?(line) unused_letters = ('a'..'z').to_a - line.downcase.chars.to_a unused_letters.empty? end def categorize file_pangram = File.new('pangram.txt', 'w') file_palindrome = File.new('palindrome.txt', 'w') file_quotes = File.new('quotes.txt','w') File.open('ruby1.txt','r') do |file| while line = file.gets if(line.reverse == line) file_palindrome.write line elsif(pangram?(line)== true) file_pangram.write line else file_quotes.write line end end end file.close file_pangram.close file_palindrome.close file_quotes.close end end my_ruby_assignment = PPQ.new my_ruby_assignment.categorize
I'm partial to simpler syntax, something like def pangram?(line) ('a'..'z').all? { |word| line.downcase.include? (word) } end if pangram?(line) then file_pangram.write line end
def pangram?(string) str = string.chars.map(&:downcase) letters =('a'..'z').to_a result = true letters.each do |l| if !(str.include? l.downcase) result = false break end end result end
Compact C Folding in Vim
I'm trying to make a simple Vim script that would create very compact top-level folds for c files. Ideally, if it was run on this code: static void funca(...) { ... } /* Example comment */ static void funcb(...) { ... } Then it would create folds which would look like this when closed: +-- x Lines: static void funca(...)---------------------- +-- x Lines: static void funcb(...)---------------------- So basically it would be like foldmethod=syntax with foldlevel=1, except that each fold would start one line further up, and would extend further down to include all following blank lines. I know how to make one of these folds (assuming foldmethod=manual): /^{<cr>kVnn?^$<cr>zf But I'm not sure how to put it into a function. This is my effort: function Cfold() set foldmethod=manual " Manual folds ggzE " Delete all folds while (/^{<cr>) " Somehow loop through each match kVnn?^$<cr>zf " This would work fine except for the last function endwhile endfunction map <Leader>f :call Cfold()<cr> But it isn't valid, I'm not entirely sure how functions work. Also, it won't work for the last function in the file, since it won't find '^{' again. If someone could help me get this working, and somehow add a case for the last function in a file, I would be extremely grateful. Thanks in advance :)
You can create folds programmatically using the foldexpr and foldtext. Try this, though you may have to tweak CFoldLevel so it doesn't swallow non-function parts of the code: function! CFoldLevel(lnum) let line = getline(a:lnum) if line =~ '^/\*' return '>1' " A new fold of level 1 starts here. else return '1' " This line has a foldlevel of 1. endif endfunction function! CFoldText() " Look through all of the folded text for the function signature. let signature = '' let i = v:foldstart while signature == '' && i < v:foldend let line = getline(i) if line =~ '\w\+(.*)$' let signature = line endif let i = i + 1 endwhile " Return what the fold should show when folded. return '+-- ' . (v:foldend - v:foldstart) . ' Lines: ' . signature . ' ' endfunction function! CFold() set foldenable set foldlevel=0 set foldmethod=expr set foldexpr=CFoldLevel(v:lnum) set foldtext=CFoldText() set foldnestmax=1 endfunction See :help 'foldexpr' for more details.