145 | | |
146 | | |
| 145 | == Examples == |
| 146 | |
| 147 | === Basic queries === |
| 148 | As you can read in the introduction, in this language we build difficult queries from lot of very simple queries. Here are some examples for simple ones: |
| 149 | |
| 150 | {{{ |
| 151 | @fun.refs |
| 152 | }}} |
| 153 | Returns a list of expressions which call the pointed function. |
| 154 | |
| 155 | {{{ |
| 156 | @file.funs.calls |
| 157 | }}} |
| 158 | Returns all function calls from current module group by the module's own functions. |
| 159 | |
| 160 | {{{ |
| 161 | @file.funs[arity==3] |
| 162 | }}} |
| 163 | Returns all functions which have 3 arguments. |
| 164 | |
| 165 | === Advanced queries === |
| 166 | Let's see some useful queries: |
| 167 | |
| 168 | {{{ |
| 169 | @file.funs.vars[name=="Expl"] |
| 170 | }}} |
| 171 | Returns all functions which have a variable named "Expl". It useful when we want to know which functions use variables with same name. |
| 172 | |
| 173 | {{{ |
| 174 | mods[name=="io"].funs[name==format].refs |
| 175 | }}} |
| 176 | Returns all io:format calls, this query is very useful when you have finished your software, and you want to find all debug messages. |
| 177 | |
| 178 | {{{ |
| 179 | @expr.origin |
| 180 | }}} |
| 181 | For example we stand in a variable, and run this query, we get information about the variable gets its value from where. This functionality uses [wiki:DataFlow data-flow analysis]. |
| 182 | |
| 183 | {{{ |
| 184 | @fun.refs.origin |
| 185 | }}} |
| 186 | Returns information about the function gets its return value from where and how its calculated. |
| 187 | |
| 188 | === Checking coding convensions === |
| 189 | |
| 190 | In !RefactorErl, [wiki:MetricQuery metrics] can be applied to modules or to functions. Modules are equivalent to {{{file}}} entities in the semantic query language, and functions are equivalent to {{{function}}} entities. We can say that a metric is a kind of property belongs to a {{{file}}} or {{{function}}} entity, so we can simply add the proper metrics to the properties of entities. |
| 191 | |
| 192 | Usually we have some coding conventions applied to our modules or functions. With our extended semantic query language we can check these conventions, and filter improper modules or functions. Hereinafter we present some design rules and some metrics to check these rules. |
| 193 | |
| 194 | ''' Rule1. A module should not contain more then 400 lines.''' |
| 195 | |
| 196 | When we would like to filter modules containing more than 400 effective lines of code, we have to load our modules to !RefactorErl system, and enter the following query: |
| 197 | {{{ |
| 198 | modules[line_of_code > 400] |
| 199 | }}} |
| 200 | In the result we will find our too long modules. |
| 201 | |
| 202 | ''' Rule2. A function should not contain more then 15 to 20 lines.''' |
| 203 | |
| 204 | When we would like to check, which functions do not fulfil this convention in our modules loaded into the !RefactorErl database, we use the following query: |
| 205 | {{{ |
| 206 | modules.funs[line_of_code > 20] |
| 207 | }}} |
| 208 | |
| 209 | ''' Rule3. Use at most two level of nesting, do not write deeply nested code.''' It is achieved by dividing the code into shorter functions. |
| 210 | |
| 211 | With one of our metrics we can count the nesting level of case expressions, so we can filter functions with more than two maximum depth of cases. In this example, we would like to get the result just from our actual module. |
| 212 | {{{ |
| 213 | @file.funs[max_depth_of_cases > 2] |
| 214 | }}} |
| 215 | |
| 216 | If we just would like to know, whether all of the functions fulfil this convention or not, we can simply query the maximum nesting level of cases in the whole module. If this value is more than two, there is at least one function containing deeply nested cases. |
| 217 | {{{ |
| 218 | @file.max_depth_of_cases |
| 219 | }}} |
| 220 | |
| 221 | At least, let's filter modules containing functions with too deeply nested cases. |
| 222 | {{{ |
| 223 | mods[max_depth_of_cases > 2] |
| 224 | }}} |
| 225 | |
| 226 | ''' Rule4. Use no more than 80 characters on a line.''' |
| 227 | |
| 228 | We can filter all of the functions, which contains lines with more than 80 characters with the following query: |
| 229 | {{{ |
| 230 | mods.funs[max_length_of_line > 80] |
| 231 | }}} |
| 232 | |
| 233 | ''' Rule5. Use space after commas.''' |
| 234 | |
| 235 | We have a metric which returns with the number of cases when we do not fulfil this convention. When a modul or a function breaks this rule, the result of the metric will be more, then 0. |
| 236 | |
| 237 | Filter functions containing at least one case when whitespace misses after |
| 238 | a comma: |
| 239 | {{{ |
| 240 | mods.funs[no_space_after_comma > 0] |
| 241 | }}} |
| 242 | |
| 243 | ''' Rule6. Every recursive function should tail recursive.''' |
| 244 | |
| 245 | Tail recursion means that we have no recursive call (either direct or indirect) in our function, just in the last expression. Filter functions that recursive, but not tail recursive: |
| 246 | {{{ |
| 247 | mods.funs[is_tail_recursive == non_tail_rec] |
| 248 | }}} |
| 249 | |
| 250 | |
| 251 | |