Skip to content

Commit

Permalink
LineBreakBear.py: Add it
Browse files Browse the repository at this point in the history
It adds a basic LineBreakBear and its tests.
  • Loading branch information
aptrishu committed Mar 21, 2017
1 parent 4219617 commit 403caa5
Show file tree
Hide file tree
Showing 2 changed files with 206 additions and 0 deletions.
132 changes: 132 additions & 0 deletions bears/general/LineBreakBear.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from queue import Queue

from coalib.results.AbsolutePosition import AbsolutePosition
from coalib.results.Diff import Diff
from coalib.bearlib.languages.LanguageDefinition import LanguageDefinition
from coalib.bears.LocalBear import LocalBear
from coalib.results.Result import Result, RESULT_SEVERITY
from coalib.results.SourceRange import SourceRange
from coalib.bearlib.spacing.SpacingHelper import SpacingHelper

from bears.general.AnnotationBear import AnnotationBear
from bears.general.RangeHelpers import get_specified_block_range
from bears.general.LineLengthBear import LineLengthBear


class LineBreakBear(LocalBear):
AUTHORS = {'The coala developers'}
AUTHORS_EMAILS = {'[email protected]'}
LICENSE = 'AGPL-3.0'
CAN_FIX = {'Formatting'}

def run(self,
filename,
file,
language: str,
dependency_results,
use_spaces=True,
indentation_width: int=SpacingHelper.DEFAULT_TAB_WIDTH,
max_line_length: int=79,
coalang_dir: str=None):
"""
Runs the LineLengthBear and suggests alternate solutions where lines
exceed the max_line_length.
:param filename:
Name of the file that needs to be checked.
:param file:
File that needs to be checked in the form of a list of strings.
:param language:
Language of the file it is running on.
:param dependency_results:
Results given by the AnnotationBear and the LineLengthBear.
:param use_spaces:
Inserts spaces instead of tabs for indentation.
:param tab_width:
No. of spaces to add before the newly created line.
:param max_line_length:
Maximum number of characters for a line, the newline character
being excluded.
:param dependency_results:
Results given by the AnnotationBear.
:param coalang_dir:
Full path of external directory containing the coalang
file for language.
"""
encapsulators = dict(LanguageDefinition(
language,
coalang_dir=coalang_dir)["encapsulators"])

# Get all lines which are over max_line_length
line_length_bear = LineLengthBear(self.section, Queue())
line_length_results = list(line_length_bear.execute(filename, file))

affected_lines = [_range.start.line
for result in line_length_results
for _range in result.affected_code]
annotation_dict = dependency_results[AnnotationBear.name][0].contents

# Get all positions of encapsulators
encaps_pos = sorted(tuple(_range
for encapsulator in encapsulators
for _range in get_specified_block_range(
file,
filename,
encapsulator,
encapsulators[encapsulator],
annotation_dict)))
print(encaps_pos)
indent = indentation_width*" " if use_spaces else "\t"

suggested_positions = self._find_breakable_encapsulators(
file,
filename,
affected_lines,
max_line_length,
encaps_pos)
new_file = self._break_after_position(file,
indent,
suggested_positions)
if new_file != list(file):
wholediff = Diff.from_string_arrays(file, new_file)
for diff in wholediff.split_diff():
yield Result(
self,
'Following is a suggestion to break this long line',
severity=RESULT_SEVERITY.INFO,
affected_code=(diff.range(filename),),
diffs={filename: diff})

def _break_after_position(self,
file,
indent,
suggested_positions):
new_file = list(file)
for position in suggested_positions:
new_line = (indent +
file[position.line - 1][position.column:])
new_file.insert(position.line, new_line)
new_file[position.line - 1] = new_file[position.line - 1][
:position.column] + '\n'
return new_file

def _find_breakable_encapsulators(self,
file,
filename,
affected_lines,
max_line_length,
encapsulators):
positions = []
for line in affected_lines:
last_encaps = None
for encaps in encapsulators:
if (encaps.start.line == line and
encaps.start.column < max_line_length):
last_encaps = encaps.start
if last_encaps:
positions.append(last_encaps)
return tuple(positions)

@staticmethod
def get_dependencies():
return [AnnotationBear] # pragma: no cover
74 changes: 74 additions & 0 deletions tests/general/LineBreakBearTest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import os
import unittest
from queue import Queue

from coalib.settings.Section import Section
from coalib.settings.Setting import Setting
from coala_utils.string_processing.Core import escape
from bears.general.LineBreakBear import LineBreakBear
from bears.general.AnnotationBear import AnnotationBear
from bears.general.LineLengthBear import LineLengthBear


class LineBreakBearTest(unittest.TestCase):

def setUp(self):
self.section = Section("")
self.section.append(Setting('language', 'test'))
self.section.append(Setting('max_line_length', 10))
self.section.append(Setting('coalang_dir', escape(os.path.join(
os.path.dirname(__file__), "test_files"), '\\')))
self.annot_uut = AnnotationBear(self.section, Queue())

def get_results(self, file, section=None):
if section is None:
section = self.section
annot_results = self.annot_uut.execute("file", file)
uut = LineBreakBear(section, Queue())
arg_dict = {'dependency_results':
{AnnotationBear.__name__:
list(annot_results)},
'file': file}
return list(uut.run_bear_from_section(["file"], arg_dict))

def test_break_on_encapsulators(self):

file = "text(greater than 10 letters)\n".splitlines(True)

changed_file = ("text(\n"
" greater than 10 letters)\n").splitlines(True)

results = self.get_results(file)

self.assertEqual(changed_file, results[0].diffs["file"].modified)

file = "func(p1,(p2,p3,p4,p5))\n".splitlines(True)

changed_file = ("func(p1,(\n"
" p2,p3,p4,p5))\n").splitlines(True)
results = self.get_results(file)

self.assertEqual(changed_file, results[0].diffs["file"].modified)

# Testing encapsulator after max_line_length
file = "very_very_long_func(p1)\n".splitlines(True)
results = self.get_results(file)
self.assertEqual(results, [])

# Test different types of encapsulators
file = "func(p1,[p2,p3,p4,p5])\n".splitlines(True)
changed_file = ("func(p1,[\n"
" p2,p3,p4,p5])\n").splitlines(True)
results = self.get_results(file)
self.assertEqual(changed_file, results[0].diffs["file"].modified)

def test_settings(self):

file = "func(p1,(p2,p3,p4,p5))\n".splitlines(True)

changed_file = ("func(p1,(\n"
"\tp2,p3,p4,p5))\n").splitlines(True)
self.section.append(Setting('use_spaces', False))
results = self.get_results(file)

self.assertEqual(changed_file, results[0].diffs["file"].modified)

0 comments on commit 403caa5

Please sign in to comment.